Merge "Fix issue #8176917: Stabillity : Native Crash :"
diff --git a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
index 033a598..d82b9a3 100644
--- a/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
+++ b/core/java/android/accessibilityservice/AccessibilityServiceInfo.java
@@ -399,6 +399,13 @@
}
/**
+ * @hide
+ */
+ public void setComponentName(ComponentName component) {
+ mId = component.flattenToShortString();
+ }
+
+ /**
* The accessibility service id.
* <p>
* <strong>Generated by the system.</strong>
@@ -515,6 +522,33 @@
}
@Override
+ public int hashCode() {
+ return 31 * 1 + ((mId == null) ? 0 : mId.hashCode());
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj) {
+ return true;
+ }
+ if (obj == null) {
+ return false;
+ }
+ if (getClass() != obj.getClass()) {
+ return false;
+ }
+ AccessibilityServiceInfo other = (AccessibilityServiceInfo) obj;
+ if (mId == null) {
+ if (other.mId != null) {
+ return false;
+ }
+ } else if (!mId.equals(other.mId)) {
+ return false;
+ }
+ return true;
+ }
+
+ @Override
public String toString() {
StringBuilder stringBuilder = new StringBuilder();
appendEventTypes(stringBuilder, eventTypes);
diff --git a/core/java/android/content/pm/PackageManager.java b/core/java/android/content/pm/PackageManager.java
index d80598c..c507245 100644
--- a/core/java/android/content/pm/PackageManager.java
+++ b/core/java/android/content/pm/PackageManager.java
@@ -666,6 +666,15 @@
public static final int INSTALL_FAILED_INTERNAL_ERROR = -110;
/**
+ * Installation failed return code: this is passed to the {@link IPackageInstallObserver} by
+ * {@link #installPackage(android.net.Uri, IPackageInstallObserver, int)}
+ * if the system failed to install the package because the user is restricted from installing
+ * apps.
+ * @hide
+ */
+ public static final int INSTALL_FAILED_USER_RESTRICTED = -111;
+
+ /**
* Flag parameter for {@link #deletePackage} to indicate that you don't want to delete the
* package's data directory.
*
@@ -710,6 +719,15 @@
public static final int DELETE_FAILED_DEVICE_POLICY_MANAGER = -2;
/**
+ * Deletion failed return code: this is passed to the
+ * {@link IPackageDeleteObserver} by {@link #deletePackage()} if the system
+ * failed to delete the package since the user is restricted.
+ *
+ * @hide
+ */
+ public static final int DELETE_FAILED_USER_RESTRICTED = -3;
+
+ /**
* Return code that is passed to the {@link IPackageMoveObserver} by
* {@link #movePackage(android.net.Uri, IPackageMoveObserver)} when the
* package has been successfully moved by the system.
diff --git a/core/java/android/os/IUserManager.aidl b/core/java/android/os/IUserManager.aidl
index ec02ae0..34c9740 100644
--- a/core/java/android/os/IUserManager.aidl
+++ b/core/java/android/os/IUserManager.aidl
@@ -17,6 +17,7 @@
package android.os;
+import android.os.Bundle;
import android.os.ParcelFileDescriptor;
import android.content.pm.UserInfo;
import android.graphics.Bitmap;
@@ -37,4 +38,6 @@
void wipeUser(int userHandle);
int getUserSerialNumber(int userHandle);
int getUserHandle(int userSerialNumber);
+ Bundle getUserRestrictions(int userHandle);
+ void setUserRestrictions(in Bundle restrictions, int userHandle);
}
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index d73f99a..e4a5e7f 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -35,6 +35,42 @@
private final IUserManager mService;
private final Context mContext;
+ /**
+ * @hide
+ * Key for user restrictions. Specifies if a user is allowed to add or remove accounts.
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String ALLOW_MODIFY_ACCOUNTS = "modify_accounts";
+
+ /**
+ * @hide
+ * Key for user restrictions. Specifies if a user is allowed to change Wi-Fi access points.
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String ALLOW_CONFIG_WIFI = "config_wifi";
+
+ /**
+ * @hide
+ * Key for user restrictions. Specifies if a user is allowed to install applications.
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String ALLOW_INSTALL_APPS = "install_apps";
+
+ /**
+ * @hide
+ * Key for user restrictions. Specifies if a user is allowed to uninstall applications.
+ * Type: Boolean
+ * @see #setUserRestrictions(Bundle)
+ * @see #getUserRestrictions()
+ */
+ public static final String ALLOW_UNINSTALL_APPS = "uninstall_apps";
+
/** @hide */
public UserManager(Context context, IUserManager service) {
mService = service;
@@ -132,6 +168,35 @@
}
}
+ /** @hide */
+ public Bundle getUserRestrictions() {
+ return getUserRestrictions(Process.myUserHandle());
+ }
+
+ /** @hide */
+ public Bundle getUserRestrictions(UserHandle userHandle) {
+ try {
+ return mService.getUserRestrictions(userHandle.getIdentifier());
+ } catch (RemoteException re) {
+ Log.w(TAG, "Could not get user restrictions", re);
+ return Bundle.EMPTY;
+ }
+ }
+
+ /** @hide */
+ public void setUserRestrictions(Bundle restrictions) {
+ setUserRestrictions(restrictions, Process.myUserHandle());
+ }
+
+ /** @hide */
+ public void setUserRestrictions(Bundle restrictions, UserHandle userHandle) {
+ try {
+ mService.setUserRestrictions(restrictions, userHandle.getIdentifier());
+ } catch (RemoteException re) {
+ Log.w(TAG, "Could not set user restrictions", re);
+ }
+ }
+
/**
* Return the serial number for a user. This is a device-unique
* number assigned to that user; if the user is deleted and then a new
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index c3eae3a..8b1863b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -1868,6 +1868,12 @@
private static final int LAYOUT_DIRECTION_DEFAULT = LAYOUT_DIRECTION_INHERIT;
/**
+ * Default horizontal layout direction.
+ * @hide
+ */
+ static final int LAYOUT_DIRECTION_RESOLVED_DEFAULT = LAYOUT_DIRECTION_LTR;
+
+ /**
* Indicates that the view is tracking some sort of transient state
* that the app should not need to be aware of, but that the framework
* should take special care to preserve.
@@ -1916,6 +1922,12 @@
private static final int TEXT_DIRECTION_DEFAULT = TEXT_DIRECTION_INHERIT;
/**
+ * Default resolved text direction
+ * @hide
+ */
+ static final int TEXT_DIRECTION_RESOLVED_DEFAULT = TEXT_DIRECTION_FIRST_STRONG;
+
+ /**
* Bit shift to get the horizontal layout direction. (bits after LAYOUT_DIRECTION_RESOLVED)
* @hide
*/
@@ -1967,7 +1979,7 @@
* @hide
*/
static final int PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT =
- TEXT_DIRECTION_FIRST_STRONG << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT;
+ TEXT_DIRECTION_RESOLVED_DEFAULT << PFLAG2_TEXT_DIRECTION_RESOLVED_MASK_SHIFT;
/*
* Default text alignment. The text alignment of this View is inherited from its parent.
@@ -2026,6 +2038,12 @@
private static final int TEXT_ALIGNMENT_DEFAULT = TEXT_ALIGNMENT_GRAVITY;
/**
+ * Default resolved text alignment
+ * @hide
+ */
+ static final int TEXT_ALIGNMENT_RESOLVED_DEFAULT = TEXT_ALIGNMENT_GRAVITY;
+
+ /**
* Bit shift to get the horizontal layout direction. (bits after DRAG_HOVERED)
* @hide
*/
@@ -2075,7 +2093,7 @@
* Indicates whether if the view text alignment has been resolved to gravity
*/
private static final int PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT =
- TEXT_ALIGNMENT_GRAVITY << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT;
+ TEXT_ALIGNMENT_RESOLVED_DEFAULT << PFLAG2_TEXT_ALIGNMENT_RESOLVED_MASK_SHIFT;
// Accessiblity constants for mPrivateFlags2
@@ -5979,7 +5997,7 @@
final int targetSdkVersion = getContext().getApplicationInfo().targetSdkVersion;
if (targetSdkVersion < JELLY_BEAN_MR1) {
mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED;
- return LAYOUT_DIRECTION_LTR;
+ return LAYOUT_DIRECTION_RESOLVED_DEFAULT;
}
return ((mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ==
PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL) ? LAYOUT_DIRECTION_RTL : LAYOUT_DIRECTION_LTR;
@@ -11805,11 +11823,10 @@
// later to get the correct resolved value
if (!canResolveLayoutDirection()) return false;
- View parent = ((View) mParent);
// Parent has not yet resolved, LTR is still the default
- if (!parent.isLayoutDirectionResolved()) return false;
+ if (!mParent.isLayoutDirectionResolved()) return false;
- if (parent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
+ if (mParent.getLayoutDirection() == LAYOUT_DIRECTION_RTL) {
mPrivateFlags2 |= PFLAG2_LAYOUT_DIRECTION_RESOLVED_RTL;
}
break;
@@ -11842,8 +11859,7 @@
public boolean canResolveLayoutDirection() {
switch (getRawLayoutDirection()) {
case LAYOUT_DIRECTION_INHERIT:
- return (mParent != null) && (mParent instanceof ViewGroup) &&
- ((ViewGroup) mParent).canResolveLayoutDirection();
+ return (mParent != null) && mParent.canResolveLayoutDirection();
default:
return true;
}
@@ -11871,8 +11887,9 @@
/**
* @return true if layout direction has been resolved.
+ * @hide
*/
- private boolean isLayoutDirectionResolved() {
+ public boolean isLayoutDirectionResolved() {
return (mPrivateFlags2 & PFLAG2_LAYOUT_DIRECTION_RESOLVED) == PFLAG2_LAYOUT_DIRECTION_RESOLVED;
}
@@ -16905,16 +16922,15 @@
return false;
}
- View parent = ((View) mParent);
// Parent has not yet resolved, so we still return the default
- if (!parent.isTextDirectionResolved()) {
+ if (!mParent.isTextDirectionResolved()) {
mPrivateFlags2 |= PFLAG2_TEXT_DIRECTION_RESOLVED_DEFAULT;
// Resolution will need to happen again later
return false;
}
// Set current resolved direction to the same value as the parent's one
- final int parentResolvedDirection = parent.getTextDirection();
+ final int parentResolvedDirection = mParent.getTextDirection();
switch (parentResolvedDirection) {
case TEXT_DIRECTION_FIRST_STRONG:
case TEXT_DIRECTION_ANY_RTL:
@@ -16955,12 +16971,13 @@
* Check if text direction resolution can be done.
*
* @return true if text direction resolution can be done otherwise return false.
+ *
+ * @hide
*/
- private boolean canResolveTextDirection() {
+ public boolean canResolveTextDirection() {
switch (getRawTextDirection()) {
case TEXT_DIRECTION_INHERIT:
- return (mParent != null) && (mParent instanceof View) &&
- ((View) mParent).canResolveTextDirection();
+ return (mParent != null) && mParent.canResolveTextDirection();
default:
return true;
}
@@ -16990,8 +17007,10 @@
/**
* @return true if text direction is resolved.
+ *
+ * @hide
*/
- private boolean isTextDirectionResolved() {
+ public boolean isTextDirectionResolved() {
return (mPrivateFlags2 & PFLAG2_TEXT_DIRECTION_RESOLVED) == PFLAG2_TEXT_DIRECTION_RESOLVED;
}
@@ -17114,16 +17133,15 @@
// Resolution will need to happen again later
return false;
}
- View parent = (View) mParent;
// Parent has not yet resolved, so we still return the default
- if (!parent.isTextAlignmentResolved()) {
+ if (!mParent.isTextAlignmentResolved()) {
mPrivateFlags2 |= PFLAG2_TEXT_ALIGNMENT_RESOLVED_DEFAULT;
// Resolution will need to happen again later
return false;
}
- final int parentResolvedTextAlignment = parent.getTextAlignment();
+ final int parentResolvedTextAlignment = mParent.getTextAlignment();
switch (parentResolvedTextAlignment) {
case TEXT_ALIGNMENT_GRAVITY:
case TEXT_ALIGNMENT_TEXT_START:
@@ -17168,12 +17186,13 @@
* Check if text alignment resolution can be done.
*
* @return true if text alignment resolution can be done otherwise return false.
+ *
+ * @hide
*/
- private boolean canResolveTextAlignment() {
+ public boolean canResolveTextAlignment() {
switch (getRawTextAlignment()) {
case TEXT_DIRECTION_INHERIT:
- return (mParent != null) && (mParent instanceof View) &&
- ((View) mParent).canResolveTextAlignment();
+ return (mParent != null) && mParent.canResolveTextAlignment();
default:
return true;
}
@@ -17203,8 +17222,10 @@
/**
* @return true if text alignment is resolved.
+ *
+ * @hide
*/
- private boolean isTextAlignmentResolved() {
+ public boolean isTextAlignmentResolved() {
return (mPrivateFlags2 & PFLAG2_TEXT_ALIGNMENT_RESOLVED) == PFLAG2_TEXT_ALIGNMENT_RESOLVED;
}
diff --git a/core/java/android/view/ViewParent.java b/core/java/android/view/ViewParent.java
index ddff91d..4b70bc0 100644
--- a/core/java/android/view/ViewParent.java
+++ b/core/java/android/view/ViewParent.java
@@ -295,4 +295,105 @@
* @hide
*/
public void childAccessibilityStateChanged(View child);
+
+ /**
+ * Tells if this view parent can resolve the layout direction.
+ * See {@link View#setLayoutDirection(int)}
+ *
+ * @return True if this view parent can resolve the layout direction.
+ *
+ * @hide
+ */
+ public boolean canResolveLayoutDirection();
+
+ /**
+ * Tells if this view parent layout direction is resolved.
+ * See {@link View#setLayoutDirection(int)}
+ *
+ * @return True if this view parent layout direction is resolved.
+ *
+ * @hide
+ */
+ public boolean isLayoutDirectionResolved();
+
+ /**
+ * Return this view parent layout direction. See {@link View#getLayoutDirection()}
+ *
+ * @return {@link View#LAYOUT_DIRECTION_RTL} if the layout direction is RTL or returns
+ * {@link View#LAYOUT_DIRECTION_LTR} if the layout direction is not RTL.
+ *
+ * @hide
+ */
+ public int getLayoutDirection();
+
+ /**
+ * Tells if this view parent can resolve the text direction.
+ * See {@link View#setTextDirection(int)}
+ *
+ * @return True if this view parent can resolve the text direction.
+ *
+ * @hide
+ */
+ public boolean canResolveTextDirection();
+
+ /**
+ * Tells if this view parent text direction is resolved.
+ * See {@link View#setTextDirection(int)}
+ *
+ * @return True if this view parent text direction is resolved.
+ *
+ * @hide
+ */
+ public boolean isTextDirectionResolved();
+
+ /**
+ * Return this view parent text direction. See {@link View#getTextDirection()}
+ *
+ * @return the resolved text direction. Returns one of:
+ *
+ * {@link View#TEXT_DIRECTION_FIRST_STRONG}
+ * {@link View#TEXT_DIRECTION_ANY_RTL},
+ * {@link View#TEXT_DIRECTION_LTR},
+ * {@link View#TEXT_DIRECTION_RTL},
+ * {@link View#TEXT_DIRECTION_LOCALE}
+ *
+ * @hide
+ */
+ public int getTextDirection();
+
+ /**
+ * Tells if this view parent can resolve the text alignment.
+ * See {@link View#setTextAlignment(int)}
+ *
+ * @return True if this view parent can resolve the text alignment.
+ *
+ * @hide
+ */
+ public boolean canResolveTextAlignment();
+
+ /**
+ * Tells if this view parent text alignment is resolved.
+ * See {@link View#setTextAlignment(int)}
+ *
+ * @return True if this view parent text alignment is resolved.
+ *
+ * @hide
+ */
+ public boolean isTextAlignmentResolved();
+
+ /**
+ * Return this view parent text alignment. See {@link android.view.View#getTextAlignment()}
+ *
+ * @return the resolved text alignment. Returns one of:
+ *
+ * {@link View#TEXT_ALIGNMENT_GRAVITY},
+ * {@link View#TEXT_ALIGNMENT_CENTER},
+ * {@link View#TEXT_ALIGNMENT_TEXT_START},
+ * {@link View#TEXT_ALIGNMENT_TEXT_END},
+ * {@link View#TEXT_ALIGNMENT_VIEW_START},
+ * {@link View#TEXT_ALIGNMENT_VIEW_END}
+ *
+ * @hide
+ */
+ public int getTextAlignment();
}
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 2df56c3..1d86361 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -4829,6 +4829,51 @@
postSendWindowContentChangedCallback(child);
}
+ @Override
+ public boolean canResolveLayoutDirection() {
+ return true;
+ }
+
+ @Override
+ public boolean isLayoutDirectionResolved() {
+ return true;
+ }
+
+ @Override
+ public int getLayoutDirection() {
+ return View.LAYOUT_DIRECTION_RESOLVED_DEFAULT;
+ }
+
+ @Override
+ public boolean canResolveTextDirection() {
+ return true;
+ }
+
+ @Override
+ public boolean isTextDirectionResolved() {
+ return true;
+ }
+
+ @Override
+ public int getTextDirection() {
+ return View.TEXT_DIRECTION_RESOLVED_DEFAULT;
+ }
+
+ @Override
+ public boolean canResolveTextAlignment() {
+ return true;
+ }
+
+ @Override
+ public boolean isTextAlignmentResolved() {
+ return true;
+ }
+
+ @Override
+ public int getTextAlignment() {
+ return View.TEXT_ALIGNMENT_RESOLVED_DEFAULT;
+ }
+
private View getCommonPredecessor(View first, View second) {
if (mAttachInfo != null) {
if (mTempHashSet == null) {
diff --git a/core/jni/android_media_AudioSystem.cpp b/core/jni/android_media_AudioSystem.cpp
index 631cdae..0827f7c 100644
--- a/core/jni/android_media_AudioSystem.cpp
+++ b/core/jni/android_media_AudioSystem.cpp
@@ -76,6 +76,15 @@
}
static jboolean
+android_media_AudioSystem_isStreamActiveRemotely(JNIEnv *env, jobject thiz, jint stream,
+ jint inPastMs)
+{
+ bool state = false;
+ AudioSystem::isStreamActiveRemotely((audio_stream_type_t) stream, &state, inPastMs);
+ return state;
+}
+
+static jboolean
android_media_AudioSystem_isSourceActive(JNIEnv *env, jobject thiz, jint source)
{
bool state = false;
@@ -270,6 +279,7 @@
{"muteMicrophone", "(Z)I", (void *)android_media_AudioSystem_muteMicrophone},
{"isMicrophoneMuted", "()Z", (void *)android_media_AudioSystem_isMicrophoneMuted},
{"isStreamActive", "(II)Z", (void *)android_media_AudioSystem_isStreamActive},
+ {"isStreamActiveRemotely","(II)Z", (void *)android_media_AudioSystem_isStreamActiveRemotely},
{"isSourceActive", "(I)Z", (void *)android_media_AudioSystem_isSourceActive},
{"setDeviceConnectionState", "(IILjava/lang/String;)I", (void *)android_media_AudioSystem_setDeviceConnectionState},
{"getDeviceConnectionState", "(ILjava/lang/String;)I", (void *)android_media_AudioSystem_getDeviceConnectionState},
diff --git a/data/etc/platform.xml b/data/etc/platform.xml
index cf04b5c..d986c1e 100644
--- a/data/etc/platform.xml
+++ b/data/etc/platform.xml
@@ -122,71 +122,6 @@
others should have a fairly open environment in which to
interact with the system. -->
- <!-- Standard permissions granted to the shell. -->
- <assign-permission name="android.permission.WRITE_EXTERNAL_STORAGE" uid="shell" />
- <assign-permission name="android.permission.SEND_SMS" uid="shell" />
- <assign-permission name="android.permission.CALL_PHONE" uid="shell" />
- <assign-permission name="android.permission.READ_CONTACTS" uid="shell" />
- <assign-permission name="android.permission.WRITE_CONTACTS" uid="shell" />
- <assign-permission name="android.permission.READ_CALENDAR" uid="shell" />
- <assign-permission name="android.permission.WRITE_CALENDAR" uid="shell" />
- <assign-permission name="android.permission.READ_USER_DICTIONARY" uid="shell" />
- <assign-permission name="android.permission.WRITE_USER_DICTIONARY" uid="shell" />
- <assign-permission name="android.permission.ACCESS_FINE_LOCATION" uid="shell" />
- <assign-permission name="android.permission.ACCESS_COARSE_LOCATION" uid="shell" />
- <assign-permission name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" uid="shell" />
- <assign-permission name="android.permission.ACCESS_NETWORK_STATE" uid="shell" />
- <assign-permission name="android.permission.ACCESS_WIFI_STATE" uid="shell" />
- <assign-permission name="android.permission.BLUETOOTH" uid="shell" />
- <assign-permission name="android.permission.EXPAND_STATUS_BAR" uid="shell" />
- <!-- System tool permissions granted to the shell. -->
- <assign-permission name="android.permission.GET_TASKS" uid="shell" />
- <assign-permission name="android.permission.CHANGE_CONFIGURATION" uid="shell" />
- <assign-permission name="android.permission.REORDER_TASKS" uid="shell" />
- <assign-permission name="android.permission.SET_ANIMATION_SCALE" uid="shell" />
- <assign-permission name="android.permission.SET_PREFERRED_APPLICATIONS" uid="shell" />
- <assign-permission name="android.permission.WRITE_SETTINGS" uid="shell" />
- <assign-permission name="android.permission.WRITE_SECURE_SETTINGS" uid="shell" />
- <assign-permission name="android.permission.BROADCAST_STICKY" uid="shell" />
- <!-- Development tool permissions granted to the shell. -->
- <assign-permission name="android.permission.SET_DEBUG_APP" uid="shell" />
- <assign-permission name="android.permission.SET_PROCESS_LIMIT" uid="shell" />
- <assign-permission name="android.permission.SET_ALWAYS_FINISH" uid="shell" />
- <assign-permission name="android.permission.DUMP" uid="shell" />
- <assign-permission name="android.permission.SIGNAL_PERSISTENT_PROCESSES" uid="shell" />
- <assign-permission name="android.permission.KILL_BACKGROUND_PROCESSES" uid="shell" />
- <!-- Internal permissions granted to the shell. -->
- <assign-permission name="android.permission.FORCE_BACK" uid="shell" />
- <assign-permission name="android.permission.BATTERY_STATS" uid="shell" />
- <assign-permission name="android.permission.INTERNAL_SYSTEM_WINDOW" uid="shell" />
- <assign-permission name="android.permission.INJECT_EVENTS" uid="shell" />
- <assign-permission name="android.permission.RETRIEVE_WINDOW_CONTENT" uid="shell" />
- <assign-permission name="android.permission.SET_ACTIVITY_WATCHER" uid="shell" />
- <assign-permission name="android.permission.READ_INPUT_STATE" uid="shell" />
- <assign-permission name="android.permission.SET_ORIENTATION" uid="shell" />
- <assign-permission name="android.permission.INSTALL_PACKAGES" uid="shell" />
- <assign-permission name="android.permission.CLEAR_APP_USER_DATA" uid="shell" />
- <assign-permission name="android.permission.DELETE_CACHE_FILES" uid="shell" />
- <assign-permission name="android.permission.DELETE_PACKAGES" uid="shell" />
- <assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="shell" />
- <assign-permission name="android.permission.READ_FRAME_BUFFER" uid="shell" />
- <assign-permission name="android.permission.DEVICE_POWER" uid="shell" />
- <assign-permission name="android.permission.INSTALL_LOCATION_PROVIDER" uid="shell" />
- <assign-permission name="android.permission.BACKUP" uid="shell" />
- <assign-permission name="android.permission.FORCE_STOP_PACKAGES" uid="shell" />
- <assign-permission name="android.permission.STOP_APP_SWITCHES" uid="shell" />
- <assign-permission name="android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY" uid="shell" />
- <assign-permission name="android.permission.GRANT_REVOKE_PERMISSIONS" uid="shell" />
- <assign-permission name="android.permission.SET_KEYBOARD_LAYOUT" uid="shell" />
- <assign-permission name="android.permission.GET_DETAILED_TASKS" uid="shell" />
- <assign-permission name="android.permission.SET_SCREEN_COMPATIBILITY" uid="shell" />
- <assign-permission name="android.permission.READ_EXTERNAL_STORAGE" uid="shell" />
- <assign-permission name="android.permission.WRITE_EXTERNAL_STORAGE" uid="shell" />
- <assign-permission name="android.permission.INTERACT_ACROSS_USERS" uid="shell" />
- <assign-permission name="android.permission.INTERACT_ACROSS_USERS_FULL" uid="shell" />
- <assign-permission name="android.permission.MANAGE_USERS" uid="shell" />
- <assign-permission name="android.permission.BLUETOOTH_STACK" uid="shell" />
-
<assign-permission name="android.permission.MODIFY_AUDIO_SETTINGS" uid="media" />
<assign-permission name="android.permission.ACCESS_DRM" uid="media" />
<assign-permission name="android.permission.ACCESS_SURFACE_FLINGER" uid="media" />
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 035b282..2e4fa4b 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -1526,6 +1526,16 @@
/**
* @hide
+ * Checks whether any music or media is actively playing on a remote device (e.g. wireless
+ * display). Note that BT audio sinks are not considered remote devices.
+ * @return true if {@link AudioManager#STREAM_MUSIC} is active on a remote device
+ */
+ public boolean isMusicActiveRemotely() {
+ return AudioSystem.isStreamActiveRemotely(STREAM_MUSIC, 0);
+ }
+
+ /**
+ * @hide
* Checks whether speech recognition is active
* @return true if a recording with source {@link MediaRecorder.AudioSource#VOICE_RECOGNITION}
* is underway.
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index dde2979..4a33743 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -111,6 +111,14 @@
public static native boolean isStreamActive(int stream, int inPastMs);
/*
+ * Checks whether the specified stream type is active on a remotely connected device. The notion
+ * of what constitutes a remote device is enforced by the audio policy manager of the platform.
+ *
+ * return true if any track playing on this stream is active on a remote device.
+ */
+ public static native boolean isStreamActiveRemotely(int stream, int inPastMs);
+
+ /*
* Checks whether the specified audio source is active.
*
* return true if any recorder using this source is currently recording
diff --git a/packages/Shell/Android.mk b/packages/Shell/Android.mk
new file mode 100644
index 0000000..f993ab5
--- /dev/null
+++ b/packages/Shell/Android.mk
@@ -0,0 +1,11 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_MODULE_TAGS := optional
+
+LOCAL_SRC_FILES := $(call all-subdir-java-files)
+
+LOCAL_PACKAGE_NAME := Shell
+LOCAL_CERTIFICATE := platform
+
+include $(BUILD_PACKAGE)
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
new file mode 100644
index 0000000..b42db45
--- /dev/null
+++ b/packages/Shell/AndroidManifest.xml
@@ -0,0 +1,74 @@
+<manifest xmlns:android="http://schemas.android.com/apk/res/android"
+ package="com.android.shell"
+ coreApp="true"
+ android:sharedUserId="android.uid.shell"
+ >
+
+ <!-- Standard permissions granted to the shell. -->
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.SEND_SMS" />
+ <uses-permission android:name="android.permission.CALL_PHONE" />
+ <uses-permission android:name="android.permission.READ_CONTACTS" />
+ <uses-permission android:name="android.permission.WRITE_CONTACTS" />
+ <uses-permission android:name="android.permission.READ_CALENDAR" />
+ <uses-permission android:name="android.permission.WRITE_CALENDAR" />
+ <uses-permission android:name="android.permission.READ_USER_DICTIONARY" />
+ <uses-permission android:name="android.permission.WRITE_USER_DICTIONARY" />
+ <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
+ <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />
+ <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
+ <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
+ <uses-permission android:name="android.permission.BLUETOOTH" />
+ <uses-permission android:name="android.permission.EXPAND_STATUS_BAR" />
+ <!-- System tool permissions granted to the shell. -->
+ <uses-permission android:name="android.permission.GET_TASKS" />
+ <uses-permission android:name="android.permission.CHANGE_CONFIGURATION" />
+ <uses-permission android:name="android.permission.REORDER_TASKS" />
+ <uses-permission android:name="android.permission.SET_ANIMATION_SCALE" />
+ <uses-permission android:name="android.permission.SET_PREFERRED_APPLICATIONS" />
+ <uses-permission android:name="android.permission.WRITE_SETTINGS" />
+ <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
+ <uses-permission android:name="android.permission.BROADCAST_STICKY" />
+ <!-- Development tool permissions granted to the shell. -->
+ <uses-permission android:name="android.permission.SET_DEBUG_APP" />
+ <uses-permission android:name="android.permission.SET_PROCESS_LIMIT" />
+ <uses-permission android:name="android.permission.SET_ALWAYS_FINISH" />
+ <uses-permission android:name="android.permission.DUMP" />
+ <uses-permission android:name="android.permission.SIGNAL_PERSISTENT_PROCESSES" />
+ <uses-permission android:name="android.permission.KILL_BACKGROUND_PROCESSES" />
+ <!-- Internal permissions granted to the shell. -->
+ <uses-permission android:name="android.permission.FORCE_BACK" />
+ <uses-permission android:name="android.permission.BATTERY_STATS" />
+ <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW" />
+ <uses-permission android:name="android.permission.INJECT_EVENTS" />
+ <uses-permission android:name="android.permission.RETRIEVE_WINDOW_CONTENT" />
+ <uses-permission android:name="android.permission.SET_ACTIVITY_WATCHER" />
+ <uses-permission android:name="android.permission.READ_INPUT_STATE" />
+ <uses-permission android:name="android.permission.SET_ORIENTATION" />
+ <uses-permission android:name="android.permission.INSTALL_PACKAGES" />
+ <uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
+ <uses-permission android:name="android.permission.DELETE_CACHE_FILES" />
+ <uses-permission android:name="android.permission.DELETE_PACKAGES" />
+ <uses-permission android:name="android.permission.ACCESS_SURFACE_FLINGER" />
+ <uses-permission android:name="android.permission.READ_FRAME_BUFFER" />
+ <uses-permission android:name="android.permission.DEVICE_POWER" />
+ <uses-permission android:name="android.permission.INSTALL_LOCATION_PROVIDER" />
+ <uses-permission android:name="android.permission.BACKUP" />
+ <uses-permission android:name="android.permission.FORCE_STOP_PACKAGES" />
+ <uses-permission android:name="android.permission.STOP_APP_SWITCHES" />
+ <uses-permission android:name="android.permission.ACCESS_CONTENT_PROVIDERS_EXTERNALLY" />
+ <uses-permission android:name="android.permission.GRANT_REVOKE_PERMISSIONS" />
+ <uses-permission android:name="android.permission.SET_KEYBOARD_LAYOUT" />
+ <uses-permission android:name="android.permission.GET_DETAILED_TASKS" />
+ <uses-permission android:name="android.permission.SET_SCREEN_COMPATIBILITY" />
+ <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
+ <uses-permission android:name="android.permission.INTERACT_ACROSS_USERS_FULL" />
+ <uses-permission android:name="android.permission.MANAGE_USERS" />
+ <uses-permission android:name="android.permission.BLUETOOTH_STACK" />
+
+ <application android:hasCode="false" android:label="@string/app_label">
+ </application>
+</manifest>
diff --git a/packages/Shell/res/values/strings.xml b/packages/Shell/res/values/strings.xml
new file mode 100644
index 0000000..50610d5
--- /dev/null
+++ b/packages/Shell/res/values/strings.xml
@@ -0,0 +1,19 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Copyright (C) 2013 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.
+-->
+
+<resources>
+ <string name="app_label">Shell</string>
+</resources>
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
index 280b368..ddfaad5 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/GlobalScreenshot.java
@@ -45,6 +45,7 @@
import android.os.Process;
import android.provider.MediaStore;
import android.util.DisplayMetrics;
+import android.util.Log;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.MotionEvent;
@@ -86,6 +87,8 @@
*/
class SaveImageInBackgroundTask extends AsyncTask<SaveImageInBackgroundData, Void,
SaveImageInBackgroundData> {
+ private static final String TAG = "SaveImageInBackgroundTask";
+
private static final String SCREENSHOTS_DIR_NAME = "Screenshots";
private static final String SCREENSHOT_FILE_NAME_TEMPLATE = "Screenshot_%s.png";
private static final String SCREENSHOT_SHARE_SUBJECT_TEMPLATE = "Screenshot (%s)";
@@ -138,6 +141,7 @@
(shortSide - mImageHeight) / 2);
c.drawBitmap(data.image, matrix, paint);
c.drawColor(0x40FFFFFF);
+ c.setBitmap(null);
Bitmap croppedIcon = Bitmap.createScaledBitmap(preview, iconSize, iconSize, true);
@@ -167,6 +171,8 @@
mNotificationBuilder.setLargeIcon(croppedIcon);
// But we still don't set it for the expanded view, allowing the smallIcon to show here.
mNotificationStyle.bigLargeIcon(null);
+
+ Log.d(TAG, "SaveImageInBackgroundTask constructor");
}
@Override
@@ -174,6 +180,7 @@
if (params.length != 1) return null;
if (isCancelled()) {
params[0].clearImage();
+ Log.d(TAG, "doInBackground cancelled");
return null;
}
@@ -238,6 +245,7 @@
// mounted
params[0].clearImage();
params[0].result = 1;
+ Log.d(TAG, "doInBackground failed");
}
// Recycle the bitmap data
@@ -245,6 +253,7 @@
image.recycle();
}
+ Log.d(TAG, "doInBackground complete");
return params[0];
}
@@ -253,6 +262,7 @@
if (isCancelled()) {
params.finisher.run();
params.clearImage();
+ Log.d(TAG, "onPostExecute cancelled");
return;
}
@@ -280,6 +290,7 @@
mNotificationManager.notify(mNotificationId, n);
}
params.finisher.run();
+ Log.d(TAG, "onPostExecute complete");
}
}
@@ -290,6 +301,8 @@
* type of gallery?
*/
class GlobalScreenshot {
+ private static final String TAG = "GlobalScreenshot";
+
private static final int SCREENSHOT_NOTIFICATION_ID = 789;
private static final int SCREENSHOT_FLASH_TO_PEAK_DURATION = 130;
private static final int SCREENSHOT_DROP_IN_DURATION = 430;
@@ -381,12 +394,15 @@
// Setup the Camera shutter sound
mCameraSound = new MediaActionSound();
mCameraSound.load(MediaActionSound.SHUTTER_CLICK);
+
+ Log.d(TAG, "GlobalScreenshot constructor");
}
/**
* Creates a new worker thread and saves the screenshot to the media store.
*/
private void saveScreenshotInWorkerThread(Runnable finisher) {
+ Log.d(TAG, "saveScreenshotInWorkerThread");
SaveImageInBackgroundData data = new SaveImageInBackgroundData();
data.context = mContext;
data.image = mScreenBitmap;
@@ -394,6 +410,7 @@
data.finisher = finisher;
if (mSaveInBgTask != null) {
mSaveInBgTask.cancel(false);
+ Log.d(TAG, "saveScreenshotInWorkerThread cancel");
}
mSaveInBgTask = new SaveImageInBackgroundTask(mContext, data, mNotificationManager,
SCREENSHOT_NOTIFICATION_ID).execute(data);
@@ -418,6 +435,8 @@
* Takes a screenshot of the current display and shows an animation.
*/
void takeScreenshot(Runnable finisher, boolean statusBarVisible, boolean navBarVisible) {
+ Log.d(TAG, "takeScreenshot");
+
// We need to orient the screenshot correctly (and the Surface api seems to take screenshots
// only in the natural orientation of the device :!)
mDisplay.getRealMetrics(mDisplayMetrics);
@@ -431,6 +450,8 @@
mDisplayMatrix.mapPoints(dims);
dims[0] = Math.abs(dims[0]);
dims[1] = Math.abs(dims[1]);
+
+ Log.d(TAG, "takeScreenshot requiresRotation");
}
// Take the screenshot
@@ -438,6 +459,7 @@
if (mScreenBitmap == null) {
notifyScreenshotError(mContext, mNotificationManager);
finisher.run();
+ Log.d(TAG, "takeScreenshot null bitmap");
return;
}
@@ -451,7 +473,10 @@
c.translate(-dims[0] / 2, -dims[1] / 2);
c.drawBitmap(mScreenBitmap, 0, 0, null);
c.setBitmap(null);
+ // Recycle the previous bitmap
+ mScreenBitmap.recycle();
mScreenBitmap = ss;
+ Log.d(TAG, "takeScreenshot rotation bitmap created");
}
// Optimizations
@@ -461,6 +486,7 @@
// Start the post-screenshot animation
startAnimation(finisher, mDisplayMetrics.widthPixels, mDisplayMetrics.heightPixels,
statusBarVisible, navBarVisible);
+ Log.d(TAG, "takeScreenshot startedAnimation");
}
@@ -469,6 +495,7 @@
*/
private void startAnimation(final Runnable finisher, int w, int h, boolean statusBarVisible,
boolean navBarVisible) {
+ Log.d(TAG, "startAnimation");
// Add the view for the animation
mScreenshotView.setImageBitmap(mScreenBitmap);
mScreenshotLayout.requestFocus();
@@ -477,9 +504,11 @@
if (mScreenshotAnimation != null) {
mScreenshotAnimation.end();
mScreenshotAnimation.removeAllListeners();
+ Log.d(TAG, "startAnimation reset previous animations");
}
mWindowManager.addView(mScreenshotLayout, mWindowLayoutParams);
+ Log.d(TAG, "startAnimation layout added to WM");
ValueAnimator screenshotDropInAnim = createScreenshotDropInAnimation();
ValueAnimator screenshotFadeOutAnim = createScreenshotDropOutAnimation(w, h,
statusBarVisible, navBarVisible);
@@ -495,6 +524,7 @@
// Clear any references to the bitmap
mScreenBitmap = null;
mScreenshotView.setImageBitmap(null);
+ Log.d(TAG, "startAnimation onAnimationEnd");
}
});
mScreenshotLayout.post(new Runnable() {
@@ -506,6 +536,7 @@
mScreenshotView.setLayerType(View.LAYER_TYPE_HARDWARE, null);
mScreenshotView.buildLayer();
mScreenshotAnimation.start();
+ Log.d(TAG, "startAnimation post runnable");
}
});
}
@@ -643,6 +674,7 @@
}
static void notifyScreenshotError(Context context, NotificationManager nManager) {
+ Log.d(TAG, "notifyScreenshotError");
Resources r = context.getResources();
// Clear all existing notification, compose the new notification and show it
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
index 456b5fa..1954af8 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/TakeScreenshotService.java
@@ -23,6 +23,7 @@
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
+import android.util.Log;
public class TakeScreenshotService extends Service {
private static final String TAG = "TakeScreenshotService";
@@ -37,12 +38,15 @@
final Messenger callback = msg.replyTo;
if (mScreenshot == null) {
mScreenshot = new GlobalScreenshot(TakeScreenshotService.this);
+ Log.d(TAG, "Global screenshot initialized");
}
+ Log.d(TAG, "Global screenshot captured");
mScreenshot.takeScreenshot(new Runnable() {
@Override public void run() {
Message reply = Message.obtain(null, 1);
try {
callback.send(reply);
+ Log.d(TAG, "Global screenshot completed");
} catch (RemoteException e) {
}
}
diff --git a/services/java/com/android/server/AppOpsService.java b/services/java/com/android/server/AppOpsService.java
index e94d03c..a402642 100644
--- a/services/java/com/android/server/AppOpsService.java
+++ b/services/java/com/android/server/AppOpsService.java
@@ -149,6 +149,61 @@
ServiceManager.addService(Context.APP_OPS_SERVICE, asBinder());
}
+ public void systemReady() {
+ synchronized (this) {
+ boolean changed = false;
+ for (int i=0; i<mUidOps.size(); i++) {
+ HashMap<String, Ops> pkgs = mUidOps.valueAt(i);
+ Iterator<Ops> it = pkgs.values().iterator();
+ while (it.hasNext()) {
+ Ops ops = it.next();
+ int curUid;
+ try {
+ curUid = mContext.getPackageManager().getPackageUid(ops.packageName,
+ UserHandle.getUserId(ops.uid));
+ } catch (NameNotFoundException e) {
+ curUid = -1;
+ }
+ if (curUid != ops.uid) {
+ Slog.i(TAG, "Pruning old package " + ops.packageName
+ + "/" + ops.uid + ": new uid=" + curUid);
+ it.remove();
+ changed = true;
+ }
+ }
+ if (pkgs.size() <= 0) {
+ mUidOps.removeAt(i);
+ }
+ }
+ if (changed) {
+ scheduleWriteLocked();
+ }
+ }
+ }
+
+ public void packageRemoved(int uid, String packageName) {
+ synchronized (this) {
+ HashMap<String, Ops> pkgs = mUidOps.get(uid);
+ if (pkgs != null) {
+ if (pkgs.remove(packageName) != null) {
+ if (pkgs.size() <= 0) {
+ mUidOps.remove(uid);
+ }
+ scheduleWriteLocked();
+ }
+ }
+ }
+ }
+
+ public void uidRemoved(int uid) {
+ synchronized (this) {
+ if (mUidOps.indexOfKey(uid) >= 0) {
+ mUidOps.remove(uid);
+ scheduleWriteLocked();
+ }
+ }
+ }
+
public void shutdown() {
Slog.w(TAG, "Writing app ops before shutdown...");
boolean doWrite = false;
@@ -258,6 +313,25 @@
}
repCbs.addAll(cbs);
}
+ if (mode == AppOpsManager.MODE_ALLOWED) {
+ // If going into the default mode, prune this op
+ // if there is nothing else interesting in it.
+ if (op.time == 0 && op.rejectTime == 0) {
+ Ops ops = getOpsLocked(uid, packageName, false);
+ if (ops != null) {
+ ops.remove(op.op);
+ if (ops.size() <= 0) {
+ HashMap<String, Ops> pkgOps = mUidOps.get(uid);
+ if (pkgOps != null) {
+ pkgOps.remove(ops.packageName);
+ if (pkgOps.size() <= 0) {
+ mUidOps.remove(uid);
+ }
+ }
+ }
+ }
+ }
+ }
scheduleWriteNowLocked();
}
}
@@ -368,6 +442,7 @@
if (DEBUG) Log.d(TAG, "noteOperation: allowing code " + code + " uid " + uid
+ " package " + packageName);
op.time = System.currentTimeMillis();
+ op.rejectTime = 0;
return AppOpsManager.MODE_ALLOWED;
}
}
@@ -396,6 +471,7 @@
+ " package " + packageName);
if (op.nesting == 0) {
op.time = System.currentTimeMillis();
+ op.rejectTime = 0;
op.duration = -1;
}
op.nesting++;
@@ -415,6 +491,7 @@
if (op.nesting <= 1) {
if (op.nesting == 1) {
op.duration = (int)(System.currentTimeMillis() - op.time);
+ op.time += op.duration;
} else {
Slog.w(TAG, "Finishing op nesting under-run: uid " + uid + " pkg " + packageName
+ " code " + code + " time=" + op.time + " duration=" + op.duration
@@ -454,6 +531,11 @@
pkgOps = new HashMap<String, Ops>();
mUidOps.put(uid, pkgOps);
}
+ if (uid == 0) {
+ packageName = "root";
+ } else if (uid == Process.SHELL_UID) {
+ packageName = "com.android.shell";
+ }
Ops ops = pkgOps.get(packageName);
if (ops == null) {
if (!edit) {
@@ -461,23 +543,25 @@
}
// This is the first time we have seen this package name under this uid,
// so let's make sure it is valid.
- final long ident = Binder.clearCallingIdentity();
- try {
- int pkgUid = -1;
+ if (uid != 0) {
+ final long ident = Binder.clearCallingIdentity();
try {
- pkgUid = mContext.getPackageManager().getPackageUid(packageName,
- UserHandle.getUserId(uid));
- } catch (NameNotFoundException e) {
+ int pkgUid = -1;
+ try {
+ pkgUid = mContext.getPackageManager().getPackageUid(packageName,
+ UserHandle.getUserId(uid));
+ } catch (NameNotFoundException e) {
+ }
+ if (pkgUid != uid) {
+ // Oops! The package name is not valid for the uid they are calling
+ // under. Abort.
+ Slog.w(TAG, "Bad call: specified package " + packageName
+ + " under uid " + uid + " but it is really " + pkgUid);
+ return null;
+ }
+ } finally {
+ Binder.restoreCallingIdentity(ident);
}
- if (pkgUid != uid) {
- // Oops! The package name is not valid for the uid they are calling
- // under. Abort.
- Slog.w(TAG, "Bad call: specified package " + packageName
- + " under uid " + uid + " but it is really " + pkgUid);
- return null;
- }
- } finally {
- Binder.restoreCallingIdentity(ident);
}
ops = new Ops(packageName, uid);
pkgOps.put(packageName, ops);
diff --git a/services/java/com/android/server/ConnectivityService.java b/services/java/com/android/server/ConnectivityService.java
index fb81391..6efe4c5 100644
--- a/services/java/com/android/server/ConnectivityService.java
+++ b/services/java/com/android/server/ConnectivityService.java
@@ -200,6 +200,7 @@
private int mDefaultConnectionSequence = 0;
private Object mDnsLock = new Object();
+ private int mNumDnsEntries;
private boolean mDnsOverridden = false;
private boolean mTestMode;
@@ -2479,6 +2480,17 @@
try {
mNetd.setDnsServersForInterface(iface, NetworkUtils.makeStrings(dnses), domains);
mNetd.setDefaultInterfaceForDns(iface);
+ for (InetAddress dns : dnses) {
+ ++last;
+ String key = "net.dns" + last;
+ String value = dns.getHostAddress();
+ SystemProperties.set(key, value);
+ }
+ for (int i = last + 1; i <= mNumDnsEntries; ++i) {
+ String key = "net.dns" + i;
+ SystemProperties.set(key, "");
+ }
+ mNumDnsEntries = last;
} catch (Exception e) {
if (DBG) loge("exception setting default dns interface: " + e);
}
diff --git a/services/java/com/android/server/DevicePolicyManagerService.java b/services/java/com/android/server/DevicePolicyManagerService.java
index 6a62809..18b4ec1 100644
--- a/services/java/com/android/server/DevicePolicyManagerService.java
+++ b/services/java/com/android/server/DevicePolicyManagerService.java
@@ -1889,7 +1889,7 @@
mHandler.post(new Runnable() {
public void run() {
try {
- ActivityManagerNative.getDefault().switchUser(0);
+ ActivityManagerNative.getDefault().switchUser(UserHandle.USER_OWNER);
((UserManager) mContext.getSystemService(Context.USER_SERVICE))
.removeUser(userHandle);
} catch (RemoteException re) {
diff --git a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
index c37f51f..179db12 100644
--- a/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
+++ b/services/java/com/android/server/accessibility/AccessibilityInputFilter.java
@@ -174,7 +174,7 @@
mMotionEventSequenceStarted = true;
}
} else {
- // Wait for an enter hover event to start processing.
+ // Wait for an enter hover event to start processing.
if (!mHoverEventSequenceStarted) {
if (motionEvent.getActionMasked() != MotionEvent.ACTION_HOVER_ENTER) {
return;
@@ -234,10 +234,14 @@
if (DEBUG) {
Slog.i(TAG, "Handling batched event: " + event + ", policyFlags: " + policyFlags);
}
- mPm.userActivity(event.getEventTime(), false);
- MotionEvent transformedEvent = MotionEvent.obtain(event);
- mEventHandler.onMotionEvent(transformedEvent, event, policyFlags);
- transformedEvent.recycle();
+ // Since we do batch processing it is possible that by the time the
+ // next batch is processed the event handle had been set to null.
+ if (mEventHandler != null) {
+ mPm.userActivity(event.getEventTime(), false);
+ MotionEvent transformedEvent = MotionEvent.obtain(event);
+ mEventHandler.onMotionEvent(transformedEvent, event, policyFlags);
+ transformedEvent.recycle();
+ }
}
@Override
diff --git a/services/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
index bb040bf..aadb790 100644
--- a/services/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -123,6 +123,9 @@
private static final String TEMPORARY_ENABLE_ACCESSIBILITY_UNTIL_KEYGUARD_REMOVED =
"temporaryEnableAccessibilityStateUntilKeyguardRemoved";
+ private static final ComponentName sFakeAccessibilityServiceComponentName =
+ new ComponentName("foo.bar", "FakeService");
+
private static final String FUNCTION_DUMP = "dump";
private static final char COMPONENT_NAME_SEPARATOR = ':';
@@ -157,8 +160,6 @@
private final MainHandler mMainHandler;
- private Service mUiAutomationService;
-
private Service mQueryBridge;
private AlertDialog mEnableTouchExplorationDialog;
@@ -167,6 +168,11 @@
private boolean mHasInputFilter;
+ private final Set<ComponentName> mTempComponentNameSet = new HashSet<ComponentName>();
+
+ private final List<AccessibilityServiceInfo> mTempAccessibilityServiceInfoList =
+ new ArrayList<AccessibilityServiceInfo>();
+
private final RemoteCallbackList<IAccessibilityManagerClient> mGlobalClients =
new RemoteCallbackList<IAccessibilityManagerClient>();
@@ -177,9 +183,6 @@
private final SparseArray<UserState> mUserStates = new SparseArray<UserState>();
- private final TempUserStateChangeMemento mTempStateChangeForCurrentUserMemento =
- new TempUserStateChangeMemento();
-
private int mCurrentUserId = UserHandle.USER_OWNER;
private UserState getCurrentUserStateLocked() {
@@ -224,10 +227,11 @@
return;
}
// We will update when the automation service dies.
- if (mUiAutomationService == null) {
- UserState userState = getCurrentUserStateLocked();
- populateInstalledAccessibilityServiceLocked(userState);
- manageServicesLocked(userState);
+ UserState userState = getCurrentUserStateLocked();
+ if (userState.mUiAutomationService == null) {
+ if (readConfigurationForUserStateLocked(userState)) {
+ onUserStateChangedLocked(userState);
+ }
}
}
}
@@ -239,8 +243,8 @@
if (userId != mCurrentUserId) {
return;
}
- UserState state = getUserStateLocked(userId);
- Iterator<ComponentName> it = state.mEnabledServices.iterator();
+ UserState userState = getUserStateLocked(userId);
+ Iterator<ComponentName> it = userState.mEnabledServices.iterator();
while (it.hasNext()) {
ComponentName comp = it.next();
String compPkg = comp.getPackageName();
@@ -249,13 +253,17 @@
// Update the enabled services setting.
persistComponentNamesToSettingLocked(
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
- state.mEnabledServices, userId);
+ userState.mEnabledServices, userId);
// Update the touch exploration granted services setting.
- state.mTouchExplorationGrantedServices.remove(comp);
+ userState.mTouchExplorationGrantedServices.remove(comp);
persistComponentNamesToSettingLocked(
Settings.Secure.
TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
- state.mEnabledServices, userId);
+ userState.mTouchExplorationGrantedServices, userId);
+ // We will update when the automation service dies.
+ if (userState.mUiAutomationService == null) {
+ onUserStateChangedLocked(userState);
+ }
return;
}
}
@@ -270,8 +278,8 @@
if (userId != mCurrentUserId) {
return false;
}
- UserState state = getUserStateLocked(userId);
- Iterator<ComponentName> it = state.mEnabledServices.iterator();
+ UserState userState = getUserStateLocked(userId);
+ Iterator<ComponentName> it = userState.mEnabledServices.iterator();
while (it.hasNext()) {
ComponentName comp = it.next();
String compPkg = comp.getPackageName();
@@ -283,7 +291,11 @@
it.remove();
persistComponentNamesToSettingLocked(
Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
- state.mEnabledServices, userId);
+ userState.mEnabledServices, userId);
+ // We will update when the automation service dies.
+ if (userState.mUiAutomationService == null) {
+ onUserStateChangedLocked(userState);
+ }
}
}
}
@@ -310,7 +322,13 @@
} else if (Intent.ACTION_USER_REMOVED.equals(action)) {
removeUser(intent.getIntExtra(Intent.EXTRA_USER_HANDLE, 0));
} else if (Intent.ACTION_USER_PRESENT.equals(action)) {
- restoreStateFromMementoIfNeeded();
+ // We will update when the automation service dies.
+ UserState userState = getCurrentUserStateLocked();
+ if (userState.mUiAutomationService == null) {
+ if (readConfigurationForUserStateLocked(userState)) {
+ onUserStateChangedLocked(userState);
+ }
+ }
}
}
}, UserHandle.ALL, intentFilter, null, null);
@@ -329,7 +347,7 @@
if (DEBUG) {
Slog.i(LOG_TAG, "Added global client for pid:" + Binder.getCallingPid());
}
- return getClientState(userState);
+ return userState.getClientState();
} else {
userState.mClients.register(client);
// If this client is not for the current user we do not
@@ -339,7 +357,7 @@
Slog.i(LOG_TAG, "Added user client for pid:" + Binder.getCallingPid()
+ " and userId:" + mCurrentUserId);
}
- return (resolvedUserId == mCurrentUserId) ? getClientState(userState) : 0;
+ return (resolvedUserId == mCurrentUserId) ? userState.getClientState() : 0;
}
}
}
@@ -385,7 +403,7 @@
.resolveCallingUserIdEnforcingPermissionsLocked(userId);
result = mEnabledServicesForFeedbackTempList;
result.clear();
- List<Service> services = getUserStateLocked(resolvedUserId).mServices;
+ List<Service> services = getUserStateLocked(resolvedUserId).mBoundServices;
while (feedbackType != 0) {
final int feedbackTypeBit = (1 << Integer.numberOfTrailingZeros(feedbackType));
feedbackType &= ~feedbackTypeBit;
@@ -410,7 +428,7 @@
if (resolvedUserId != mCurrentUserId) {
return;
}
- services = getUserStateLocked(resolvedUserId).mServices;
+ services = getUserStateLocked(resolvedUserId).mBoundServices;
}
for (int i = 0, count = services.size(); i < count; i++) {
Service service = services.get(i);
@@ -514,36 +532,48 @@
AccessibilityServiceInfo accessibilityServiceInfo) {
mSecurityPolicy.enforceCallingPermission(Manifest.permission.RETRIEVE_WINDOW_CONTENT,
FUNCTION_REGISTER_UI_TEST_AUTOMATION_SERVICE);
- ComponentName componentName = new ComponentName("foo.bar",
- "AutomationAccessibilityService");
+
+ accessibilityServiceInfo.setComponentName(sFakeAccessibilityServiceComponentName);
+
synchronized (mLock) {
- if (mUiAutomationService != null) {
+ UserState userState = getCurrentUserStateLocked();
+
+ if (userState.mUiAutomationService != null) {
throw new IllegalStateException("UiAutomationService " + serviceClient
+ "already registered!");
}
- // If an automation services is connected to the system all services are stopped
- // so the automation one is the only one running. Settings are not changed so when
- // the automation service goes away the state is restored from the settings.
- UserState userState = getCurrentUserStateLocked();
- unbindAllServicesLocked(userState);
- // If necessary enable accessibility and announce that.
- if (!userState.mIsAccessibilityEnabled) {
- userState.mIsAccessibilityEnabled = true;
- }
- // No touch exploration.
+ userState.mUiAutomationServiceClient = serviceClient;
+
+ // Set the temporary state.
+ userState.mIsAccessibilityEnabled = true;
userState.mIsTouchExplorationEnabled = false;
-
- // No touch enhanced web accessibility.
userState.mIsEnhancedWebAccessibilityEnabled = false;
+ userState.mIsDisplayMagnificationEnabled = false;
+ userState.mInstalledServices.add(accessibilityServiceInfo);
+ userState.mEnabledServices.clear();
+ userState.mEnabledServices.add(sFakeAccessibilityServiceComponentName);
+ userState.mTouchExplorationGrantedServices.add(sFakeAccessibilityServiceComponentName);
- // Hook the automation service up.
- mUiAutomationService = new Service(mCurrentUserId, componentName,
- accessibilityServiceInfo, true);
- mUiAutomationService.onServiceConnected(componentName, serviceClient.asBinder());
+ // Use the new state instead of settings.
+ onUserStateChangedLocked(userState);
+ }
+ }
- scheduleUpdateInputFilter(userState);
- scheduleSendStateToClientsLocked(userState);
+ public void unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient) {
+ synchronized (mLock) {
+ UserState userState = getCurrentUserStateLocked();
+ // Automation service is not bound, so pretend it died to perform clean up.
+ if (userState.mUiAutomationService != null
+ && userState.mUiAutomationService.mServiceInterface != null
+ && serviceClient != null
+ && userState.mUiAutomationService.mServiceInterface.asBinder()
+ == serviceClient.asBinder()) {
+ userState.mUiAutomationService.binderDied();
+ } else {
+ throw new IllegalStateException("UiAutomationService " + serviceClient
+ + " not registered!");
+ }
}
}
@@ -560,36 +590,26 @@
return;
}
synchronized (mLock) {
- UserState userState = getCurrentUserStateLocked();
- // Stash the old state so we can restore it when the keyguard is gone.
- mTempStateChangeForCurrentUserMemento.initialize(getCurrentUserStateLocked());
// Set the temporary state.
+ UserState userState = getCurrentUserStateLocked();
+
+ // This is a nop if UI automation is enabled.
+ if (userState.mUiAutomationService != null) {
+ return;
+ }
+
userState.mIsAccessibilityEnabled = true;
userState.mIsTouchExplorationEnabled = touchExplorationEnabled;
userState.mIsEnhancedWebAccessibilityEnabled = false;
userState.mIsDisplayMagnificationEnabled = false;
userState.mEnabledServices.clear();
userState.mEnabledServices.add(service);
+ userState.mBindingServices.clear();
userState.mTouchExplorationGrantedServices.clear();
userState.mTouchExplorationGrantedServices.add(service);
- // Update the internal state.
- performServiceManagementLocked(userState);
- scheduleUpdateInputFilter(userState);
- scheduleSendStateToClientsLocked(userState);
- }
- }
- public void unregisterUiTestAutomationService(IAccessibilityServiceClient serviceClient) {
- synchronized (mLock) {
- // Automation service is not bound, so pretend it died to perform clean up.
- if (mUiAutomationService != null && mUiAutomationService.mServiceInterface != null
- && serviceClient != null && mUiAutomationService.mServiceInterface
- .asBinder() == serviceClient.asBinder()) {
- mUiAutomationService.binderDied();
- } else {
- throw new IllegalStateException("UiAutomationService " + serviceClient
- + " not registered!");
- }
+ // User the current state instead settings.
+ onUserStateChangedLocked(userState);
}
}
@@ -695,10 +715,6 @@
private void switchUser(int userId) {
synchronized (mLock) {
- // The user switched so we do not need to restore the current user
- // state since we will fully rebuild it when he becomes current again.
- mTempStateChangeForCurrentUserMemento.clear();
-
// Disconnect from services for the old user.
UserState oldUserState = getUserStateLocked(mCurrentUserId);
unbindAllServicesLocked(oldUserState);
@@ -716,9 +732,14 @@
// The user changed.
mCurrentUserId = userId;
- // Recreate the internal state for the new user.
- mMainHandler.obtainMessage(MainHandler.MSG_SEND_RECREATE_INTERNAL_STATE,
- mCurrentUserId, 0).sendToTarget();
+ UserState userState = getCurrentUserStateLocked();
+ if (userState.mUiAutomationService != null) {
+ // Switching users disables the UI automation service.
+ userState.mUiAutomationService.binderDied();
+ } else if (readConfigurationForUserStateLocked(userState)) {
+ // Update the user state if needed.
+ onUserStateChangedLocked(userState);
+ }
if (announceNewUser) {
// Schedule announcement of the current user if needed.
@@ -734,25 +755,11 @@
}
}
- private void restoreStateFromMementoIfNeeded() {
- synchronized (mLock) {
- if (mTempStateChangeForCurrentUserMemento.mUserId != UserHandle.USER_NULL) {
- UserState userState = getCurrentUserStateLocked();
- // Restore the state from the memento.
- mTempStateChangeForCurrentUserMemento.applyTo(userState);
- mTempStateChangeForCurrentUserMemento.clear();
- // Update the internal state.
- performServiceManagementLocked(userState);
- scheduleUpdateInputFilter(userState);
- scheduleSendStateToClientsLocked(userState);
- }
- }
- }
-
private Service getQueryBridge() {
if (mQueryBridge == null) {
AccessibilityServiceInfo info = new AccessibilityServiceInfo();
- mQueryBridge = new Service(UserHandle.USER_NULL, null, info, true);
+ mQueryBridge = new Service(UserHandle.USER_NULL,
+ sFakeAccessibilityServiceComponentName, info);
}
return mQueryBridge;
}
@@ -768,8 +775,8 @@
// behavior is observed from different combinations of
// enabled accessibility services.
UserState state = getCurrentUserStateLocked();
- for (int i = state.mServices.size() - 1; i >= 0; i--) {
- Service service = state.mServices.get(i);
+ for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
+ Service service = state.mBoundServices.get(i);
if (service.mRequestTouchExplorationMode && service.mIsDefault == isDefault) {
service.notifyGesture(gestureId);
return true;
@@ -780,8 +787,8 @@
private void notifyClearAccessibilityNodeInfoCacheLocked() {
UserState state = getCurrentUserStateLocked();
- for (int i = state.mServices.size() - 1; i >= 0; i--) {
- Service service = state.mServices.get(i);
+ for (int i = state.mBoundServices.size() - 1; i >= 0; i--) {
+ Service service = state.mBoundServices.get(i);
service.notifyClearAccessibilityNodeInfoCache();
}
}
@@ -807,8 +814,8 @@
}
}
- private void populateInstalledAccessibilityServiceLocked(UserState userState) {
- userState.mInstalledServices.clear();
+ private boolean readInstalledAccessibilityServiceLocked(UserState userState) {
+ mTempAccessibilityServiceInfoList.clear();
List<ResolveInfo> installedServices = mPackageManager.queryIntentServicesAsUser(
new Intent(AccessibilityService.SERVICE_INTERFACE),
@@ -829,26 +836,53 @@
AccessibilityServiceInfo accessibilityServiceInfo;
try {
accessibilityServiceInfo = new AccessibilityServiceInfo(resolveInfo, mContext);
- userState.mInstalledServices.add(accessibilityServiceInfo);
+ mTempAccessibilityServiceInfoList.add(accessibilityServiceInfo);
} catch (XmlPullParserException xppe) {
Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", xppe);
} catch (IOException ioe) {
Slog.e(LOG_TAG, "Error while initializing AccessibilityServiceInfo", ioe);
}
}
+
+ if (!mTempAccessibilityServiceInfoList.equals(userState.mInstalledServices)) {
+ userState.mInstalledServices.clear();
+ userState.mInstalledServices.addAll(mTempAccessibilityServiceInfoList);
+ mTempAccessibilityServiceInfoList.clear();
+ return true;
+ }
+
+ mTempAccessibilityServiceInfoList.clear();
+ return false;
}
- private void populateEnabledAccessibilityServicesLocked(UserState userState) {
- populateComponentNamesFromSettingLocked(
- Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
- userState.mUserId,
- userState.mEnabledServices);
+ private boolean readEnabledAccessibilityServicesLocked(UserState userState) {
+ mTempComponentNameSet.clear();
+ readComponentNamesFromSettingLocked(Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES,
+ userState.mUserId, mTempComponentNameSet);
+ if (!mTempComponentNameSet.equals(userState.mEnabledServices)) {
+ userState.mEnabledServices.clear();
+ userState.mEnabledServices.addAll(mTempComponentNameSet);
+ mTempComponentNameSet.clear();
+ return true;
+ }
+ mTempComponentNameSet.clear();
+ return false;
}
- private void populateTouchExplorationGrantedAccessibilityServicesLocked(UserState userState) {
- populateComponentNamesFromSettingLocked(
+ private boolean readTouchExplorationGrantedAccessibilityServicesLocked(
+ UserState userState) {
+ mTempComponentNameSet.clear();
+ readComponentNamesFromSettingLocked(
Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
- userState.mUserId, userState.mTouchExplorationGrantedServices);
+ userState.mUserId, mTempComponentNameSet);
+ if (!mTempComponentNameSet.equals(userState.mTouchExplorationGrantedServices)) {
+ userState.mTouchExplorationGrantedServices.clear();
+ userState.mTouchExplorationGrantedServices.addAll(mTempComponentNameSet);
+ mTempComponentNameSet.clear();
+ return true;
+ }
+ mTempComponentNameSet.clear();
+ return false;
}
/**
@@ -862,8 +896,8 @@
boolean isDefault) {
try {
UserState state = getCurrentUserStateLocked();
- for (int i = 0, count = state.mServices.size(); i < count; i++) {
- Service service = state.mServices.get(i);
+ for (int i = 0, count = state.mBoundServices.size(); i < count; i++) {
+ Service service = state.mBoundServices.get(i);
if (service.mIsDefault == isDefault) {
if (canDispathEventLocked(service, event, state.mHandledFeedbackTypes)) {
@@ -880,25 +914,12 @@
}
}
- /**
- * Adds a service for a user.
- *
- * @param service The service to add.
- * @param userId The user id.
- */
- private void tryAddServiceLocked(Service service, int userId) {
+ private void addServiceLocked(Service service, UserState userState) {
try {
- UserState userState = getUserStateLocked(userId);
- if (userState.mServices.contains(service)) {
- return;
- }
service.linkToOwnDeath();
- userState.mServices.add(service);
+ userState.mBoundServices.add(service);
userState.mComponentNameToServiceMap.put(service.mComponentName, service);
- scheduleUpdateInputFilter(userState);
- tryEnableTouchExplorationLocked(service);
- tryEnableEnhancedWebAccessibilityLocked(service);
- } catch (RemoteException e) {
+ } catch (RemoteException re) {
/* do nothing */
}
}
@@ -909,19 +930,12 @@
* @param service The service.
* @return True if the service was removed, false otherwise.
*/
- private boolean tryRemoveServiceLocked(Service service) {
+ private void removeServiceLocked(Service service) {
UserState userState = getUserStateLocked(service.mUserId);
- final boolean removed = userState.mServices.remove(service);
- if (!removed) {
- return false;
- }
+ userState.mBoundServices.remove(service);
userState.mComponentNameToServiceMap.remove(service.mComponentName);
service.unlinkToOwnDeath();
service.dispose();
- scheduleUpdateInputFilter(userState);
- tryDisableTouchExplorationLocked(service);
- tryDisableEnhancedWebAccessibilityLocked(service);
- return removed;
}
/**
@@ -969,29 +983,11 @@
return false;
}
- /**
- * Manages services by starting enabled ones and stopping disabled ones.
- */
- private void manageServicesLocked(UserState userState) {
- final int enabledInstalledServicesCount = updateServicesStateLocked(userState);
- // No enabled installed services => disable accessibility to avoid
- // sending accessibility events with no recipient across processes.
- if (userState.mIsAccessibilityEnabled && enabledInstalledServicesCount == 0) {
- Settings.Secure.putIntForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId);
- }
- }
-
- /**
- * Unbinds all bound services for a user.
- *
- * @param userState The user state.
- */
private void unbindAllServicesLocked(UserState userState) {
- List<Service> services = userState.mServices;
+ List<Service> services = userState.mBoundServices;
for (int i = 0, count = services.size(); i < count; i++) {
Service service = services.get(i);
- if (service.unbind()) {
+ if (service.unbindLocked()) {
i--;
count--;
}
@@ -1006,7 +1002,7 @@
* @param userId The user id.
* @param outComponentNames The output component names.
*/
- private void populateComponentNamesFromSettingLocked(String settingName, int userId,
+ private void readComponentNamesFromSettingLocked(String settingName, int userId,
Set<ComponentName> outComponentNames) {
String settingValue = Settings.Secure.getStringForUser(mContext.getContentResolver(),
settingName, userId);
@@ -1047,19 +1043,11 @@
settingName, builder.toString(), userId);
}
- /**
- * Updates the state of each service by starting (or keeping running) enabled ones and
- * stopping the rest.
- *
- * @param userState The user state for which to do that.
- * @return The number of enabled installed services.
- */
- private int updateServicesStateLocked(UserState userState) {
+ private void manageServicesLocked(UserState userState) {
Map<ComponentName, Service> componentNameToServiceMap =
userState.mComponentNameToServiceMap;
boolean isEnabled = userState.mIsAccessibilityEnabled;
- int enabledInstalledServices = 0;
for (int i = 0, count = userState.mInstalledServices.size(); i < count; i++) {
AccessibilityServiceInfo installedService = userState.mInstalledServices.get(i);
ComponentName componentName = ComponentName.unflattenFromString(
@@ -1067,32 +1055,46 @@
Service service = componentNameToServiceMap.get(componentName);
if (isEnabled) {
+ // Wait for the binding if it is in process.
+ if (userState.mBindingServices.contains(componentName)) {
+ continue;
+ }
+ // No enabled installed services => disable accessibility to avoid
+ // sending accessibility events with no recipient across processes.
+ if (userState.mEnabledServices.isEmpty()) {
+ userState.mIsAccessibilityEnabled = false;
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId);
+ return;
+ }
if (userState.mEnabledServices.contains(componentName)) {
if (service == null) {
- service = new Service(userState.mUserId, componentName,
- installedService, false);
+ service = new Service(userState.mUserId, componentName, installedService);
+ } else if (userState.mBoundServices.contains(service)) {
+ continue;
}
- service.bind();
- enabledInstalledServices++;
+ service.bindLocked();
} else {
if (service != null) {
- service.unbind();
+ service.unbindLocked();
}
}
} else {
if (service != null) {
- service.unbind();
+ service.unbindLocked();
+ } else {
+ userState.mBindingServices.remove(componentName);
}
}
}
-
- return enabledInstalledServices;
}
- private void scheduleSendStateToClientsLocked(UserState userState) {
- if (mGlobalClients.getRegisteredCallbackCount() > 0
- || userState.mClients.getRegisteredCallbackCount() > 0) {
- final int clientState = getClientState(userState);
+ private void scheduleUpdateClientsIfNeededLocked(UserState userState) {
+ final int clientState = userState.getClientState();
+ if (userState.mLastSentClientState != clientState
+ && (mGlobalClients.getRegisteredCallbackCount() > 0
+ || userState.mClients.getRegisteredCallbackCount() > 0)) {
+ userState.mLastSentClientState = clientState;
mMainHandler.obtainMessage(MainHandler.MSG_SEND_STATE_TO_CLIENTS,
clientState, userState.mUserId) .sendToTarget();
}
@@ -1144,10 +1146,10 @@
}
private void showEnableTouchExplorationDialog(final Service service) {
- String label = service.mResolveInfo.loadLabel(
-
- mContext.getPackageManager()).toString();
synchronized (mLock) {
+ String label = service.mResolveInfo.loadLabel(
+ mContext.getPackageManager()).toString();
+
final UserState state = getCurrentUserStateLocked();
if (state.mIsTouchExplorationEnabled) {
return;
@@ -1167,9 +1169,12 @@
Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES,
state.mTouchExplorationGrantedServices, state.mUserId);
// Enable touch exploration.
+ UserState userState = getUserStateLocked(service.mUserId);
+ userState.mIsTouchExplorationEnabled = true;
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1,
service.mUserId);
+ onUserStateChangedLocked(userState);
}
})
.setNegativeButton(android.R.string.cancel, new OnClickListener() {
@@ -1191,92 +1196,104 @@
}
}
- private int getClientState(UserState userState) {
- int clientState = 0;
- if (userState.mIsAccessibilityEnabled) {
- clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED;
- }
- // Touch exploration relies on enabled accessibility.
- if (userState.mIsAccessibilityEnabled && userState.mIsTouchExplorationEnabled) {
- clientState |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED;
- }
- return clientState;
- }
-
- private void recreateInternalStateLocked(UserState userState) {
- populateInstalledAccessibilityServiceLocked(userState);
- populateEnabledAccessibilityServicesLocked(userState);
- populateTouchExplorationGrantedAccessibilityServicesLocked(userState);
- populatedEnhancedWebAccessibilityEnabledChangedLocked(userState);
-
- handleTouchExplorationEnabledSettingChangedLocked(userState);
- handleDisplayMagnificationEnabledSettingChangedLocked(userState);
- handleAccessibilityEnabledSettingChangedLocked(userState);
- handleTouchExplorationGrantedAccessibilityServicesChangedLocked(userState);
-
- performServiceManagementLocked(userState);
-
+ private void onUserStateChangedLocked(UserState userState) {
+ updateServicesLocked(userState);
+ updateTouchExplorationLocked(userState);
+ updateEnhancedWebAccessibilityLocked(userState);
scheduleUpdateInputFilter(userState);
- scheduleSendStateToClientsLocked(userState);
+ scheduleUpdateClientsIfNeededLocked(userState);
}
- private void handleAccessibilityEnabledSettingChangedLocked(UserState userState) {
- userState.mIsAccessibilityEnabled = Settings.Secure.getIntForUser(
- mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId) == 1;
- }
-
- private void performServiceManagementLocked(UserState userState) {
- if (userState.mIsAccessibilityEnabled ) {
+ private void updateServicesLocked(UserState userState) {
+ if (userState.mIsAccessibilityEnabled) {
manageServicesLocked(userState);
} else {
unbindAllServicesLocked(userState);
}
}
- private void handleTouchExplorationEnabledSettingChangedLocked(UserState userState) {
- userState.mIsTouchExplorationEnabled = Settings.Secure.getIntForUser(
- mContext.getContentResolver(),
- Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId) == 1;
+ private boolean readConfigurationForUserStateLocked(UserState userState) {
+ boolean somthingChanged = false;
+ somthingChanged |= readAccessibilityEnabledSettingLocked(userState);
+ somthingChanged |= readInstalledAccessibilityServiceLocked(userState);
+ somthingChanged |= readEnabledAccessibilityServicesLocked(userState);
+ somthingChanged |= readTouchExplorationGrantedAccessibilityServicesLocked(userState);
+ somthingChanged |= readTouchExplorationEnabledSettingLocked(userState);
+ somthingChanged |= readEnhancedWebAccessibilityEnabledChangedLocked(userState);
+ somthingChanged |= readDisplayMagnificationEnabledSettingLocked(userState);
+ return somthingChanged;
}
- private void handleDisplayMagnificationEnabledSettingChangedLocked(UserState userState) {
- userState.mIsDisplayMagnificationEnabled = Settings.Secure.getIntForUser(
+ private boolean readAccessibilityEnabledSettingLocked(UserState userState) {
+ final boolean accessibilityEnabled = Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_ENABLED, 0, userState.mUserId) == 1;
+ if (accessibilityEnabled != userState.mIsAccessibilityEnabled) {
+ userState.mIsAccessibilityEnabled = accessibilityEnabled;
+ return true;
+ }
+ return false;
+ }
+
+ private boolean readTouchExplorationEnabledSettingLocked(UserState userState) {
+ final boolean touchExplorationEnabled = Settings.Secure.getIntForUser(
+ mContext.getContentResolver(),
+ Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId) == 1;
+ if (touchExplorationEnabled != userState.mIsTouchExplorationEnabled) {
+ userState.mIsTouchExplorationEnabled = touchExplorationEnabled;
+ return true;
+ }
+ return false;
+ }
+
+ private boolean readDisplayMagnificationEnabledSettingLocked(UserState userState) {
+ final boolean displayMagnificationEnabled = Settings.Secure.getIntForUser(
mContext.getContentResolver(),
Settings.Secure.ACCESSIBILITY_DISPLAY_MAGNIFICATION_ENABLED,
0, userState.mUserId) == 1;
+ if (displayMagnificationEnabled != userState.mIsDisplayMagnificationEnabled) {
+ userState.mIsDisplayMagnificationEnabled = displayMagnificationEnabled;
+ return true;
+ }
+ return false;
}
- private void handleTouchExplorationGrantedAccessibilityServicesChangedLocked(
- UserState userState) {
- Settings.Secure.putIntForUser(mContext.getContentResolver(),
- Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId);
- final int serviceCount = userState.mServices.size();
+ private boolean readEnhancedWebAccessibilityEnabledChangedLocked(UserState userState) {
+ final boolean enhancedWeAccessibilityEnabled = Settings.Secure.getIntForUser(
+ mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION,
+ 0, userState.mUserId) == 1;
+ if (enhancedWeAccessibilityEnabled != userState.mIsEnhancedWebAccessibilityEnabled) {
+ userState.mIsEnhancedWebAccessibilityEnabled = enhancedWeAccessibilityEnabled;
+ return true;
+ }
+ return false;
+ }
+
+ private void updateTouchExplorationLocked(UserState userState) {
+ userState.mIsTouchExplorationEnabled = false;
+ final int serviceCount = userState.mBoundServices.size();
for (int i = 0; i < serviceCount; i++) {
- Service service = userState.mServices.get(i);
- tryEnableTouchExplorationLocked(service);
+ Service service = userState.mBoundServices.get(i);
+ if (tryEnableTouchExplorationLocked(service)) {
+ break;
+ }
}
}
- private void populatedEnhancedWebAccessibilityEnabledChangedLocked(UserState userState) {
- userState.mIsEnhancedWebAccessibilityEnabled = Settings.Secure.getIntForUser(
- mContext.getContentResolver(), Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION,
- 0, userState.mUserId) == 1;
- }
-
- private void tryEnableTouchExplorationLocked(Service service) {
+ private boolean tryEnableTouchExplorationLocked(Service service) {
if (!service.canReceiveEventsLocked() || !service.mRequestTouchExplorationMode) {
- return;
+ return false;
}
UserState userState = getUserStateLocked(service.mUserId);
if (userState.mIsTouchExplorationEnabled) {
- return;
+ return false;
}
// UI test automation service can always enable it.
if (service.mIsAutomation) {
+ userState.mIsTouchExplorationEnabled = true;
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1, service.mUserId);
- return;
+ return true;
}
if (service.mResolveInfo.serviceInfo.applicationInfo.targetSdkVersion
<= Build.VERSION_CODES.JELLY_BEAN_MR1) {
@@ -1287,11 +1304,15 @@
if (mEnableTouchExplorationDialog == null
|| (mEnableTouchExplorationDialog != null
&& !mEnableTouchExplorationDialog.isShowing())) {
- showEnableTouchExplorationDialog(service);
+ mMainHandler.obtainMessage(
+ MainHandler.MSG_SHOW_ENABLED_TOUCH_EXPLORATION_DIALOG,
+ service).sendToTarget();
}
} else {
+ userState.mIsTouchExplorationEnabled = true;
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1, service.mUserId);
+ return true;
}
} else {
// Starting in JB-MR2 we request a permission to allow a service to enable
@@ -1299,94 +1320,43 @@
if (mContext.getPackageManager().checkPermission(
android.Manifest.permission.CAN_REQUEST_TOUCH_EXPLORATION_MODE,
service.mComponentName.getPackageName()) == PackageManager.PERMISSION_GRANTED) {
+ userState.mIsTouchExplorationEnabled = true;
Settings.Secure.putIntForUser(mContext.getContentResolver(),
Settings.Secure.TOUCH_EXPLORATION_ENABLED, 1, service.mUserId);
+ return true;
}
}
+ return false;
}
- private void tryDisableTouchExplorationLocked(Service service) {
- if (!service.mRequestTouchExplorationMode) {
- return;
- }
- UserState userState = getUserStateLocked(service.mUserId);
- if (!userState.mIsTouchExplorationEnabled) {
- return;
- }
- final int serviceCount = userState.mServices.size();
+ private void updateEnhancedWebAccessibilityLocked(UserState userState) {
+ userState.mIsEnhancedWebAccessibilityEnabled = false;
+ final int serviceCount = userState.mBoundServices.size();
for (int i = 0; i < serviceCount; i++) {
- Service other = userState.mServices.get(i);
- if (other != service) {
- if (service.mResolveInfo.serviceInfo.applicationInfo.targetSdkVersion
- <= Build.VERSION_CODES.JELLY_BEAN_MR1) {
- // Up to JB-MR1 we had a white list with services that can enable touch
- // exploration. When a service is first started we show a dialog to the
- // use to get a permission to white list the service.
- if (other.mRequestTouchExplorationMode &&
- userState.mTouchExplorationGrantedServices.contains(
- service.mComponentName)) {
- // A white-listed service wants touch exploration, do not disable.
- return;
- }
- } else {
- // Starting in JB-MR2 we request a permission to allow a service to enable
- // touch exploration and do not care if the service is in the white list.
- if (other.mRequestTouchExplorationMode && (service.mIsAutomation
- || mContext.getPackageManager().checkPermission(
- android.Manifest.permission.CAN_REQUEST_TOUCH_EXPLORATION_MODE,
- service.mComponentName.getPackageName())
- == PackageManager.PERMISSION_GRANTED)) {
- // A service with permission wants touch exploration, do not disable.
- return;
- }
- }
- }
- }
- Settings.Secure.putIntForUser(mContext.getContentResolver(),
- Settings.Secure.TOUCH_EXPLORATION_ENABLED, 0, userState.mUserId);
- }
-
- private void tryEnableEnhancedWebAccessibilityLocked(Service service) {
- if (!service.canReceiveEventsLocked() || !service.mRequestEnhancedWebAccessibility ) {
- return;
- }
- UserState userState = getUserStateLocked(service.mUserId);
- if (userState.mIsEnhancedWebAccessibilityEnabled) {
- return;
- }
- // Requested and can enabled, do it.
- if (service.mRequestEnhancedWebAccessibility
- && canEnabledEnhancedWebAccessibility(service)) {
- Settings.Secure.putIntForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 1, userState.mUserId);
- }
- }
-
- private void tryDisableEnhancedWebAccessibilityLocked(Service service) {
- if (!service.mRequestEnhancedWebAccessibility) {
- return;
- }
- UserState userState = getUserStateLocked(service.mUserId);
- if (!userState.mIsEnhancedWebAccessibilityEnabled) {
- return;
- }
- final int serviceCount = userState.mServices.size();
- for (int i = 0; i < serviceCount; i++) {
- Service other = userState.mServices.get(i);
- if (other != service && other.mRequestEnhancedWebAccessibility
- && canEnabledEnhancedWebAccessibility(other)) {
- // One service requests the feature, do not disable.
+ Service service = userState.mBoundServices.get(i);
+ if (tryEnableEnhancedWebAccessibilityLocked(service)) {
return;
}
}
- Settings.Secure.putIntForUser(mContext.getContentResolver(),
- Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 0, service.mUserId);
}
- private boolean canEnabledEnhancedWebAccessibility(Service service) {
- return (service.mIsAutomation || mContext.getPackageManager().checkPermission(
+ private boolean tryEnableEnhancedWebAccessibilityLocked(Service service) {
+ if (!service.canReceiveEventsLocked() || !service.mRequestEnhancedWebAccessibility ) {
+ return false;
+ }
+ UserState userState = getUserStateLocked(service.mUserId);
+ if (userState.mIsEnhancedWebAccessibilityEnabled) {
+ return false;
+ }
+ if (service.mIsAutomation || mContext.getPackageManager().checkPermission(
android.Manifest.permission.CAN_REQUEST_ENHANCED_WEB_ACCESSIBILITY,
- service.mComponentName.getPackageName()) == PackageManager.PERMISSION_GRANTED);
+ service.mComponentName.getPackageName()) == PackageManager.PERMISSION_GRANTED) {
+ userState.mIsEnhancedWebAccessibilityEnabled = true;
+ Settings.Secure.putIntForUser(mContext.getContentResolver(),
+ Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION, 1, userState.mUserId);
+ return true;
+ }
+ return false;
}
@Override
@@ -1395,12 +1365,6 @@
synchronized (mLock) {
pw.println("ACCESSIBILITY MANAGER (dumpsys accessibility)");
pw.println();
- pw.println("Ui automation service: bound=" + (mUiAutomationService != null));
- pw.println();
- if (mUiAutomationService != null) {
- mUiAutomationService.dump(fd, pw, args);
- pw.println();
- }
final int userCount = mUserStates.size();
for (int i = 0; i < userCount; i++) {
UserState userState = mUserStates.valueAt(i);
@@ -1410,17 +1374,22 @@
pw.append(", touchExplorationEnabled=" + userState.mIsTouchExplorationEnabled);
pw.append(", displayMagnificationEnabled="
+ userState.mIsDisplayMagnificationEnabled);
+ if (userState.mUiAutomationService != null) {
+ pw.append(", ");
+ userState.mUiAutomationService.dump(fd, pw, args);
+ pw.println();
+ }
pw.append("}");
pw.println();
pw.append(" services:{");
- final int serviceCount = userState.mServices.size();
+ final int serviceCount = userState.mBoundServices.size();
for (int j = 0; j < serviceCount; j++) {
if (j > 0) {
pw.append(", ");
pw.println();
pw.append(" ");
}
- Service service = userState.mServices.get(j);
+ Service service = userState.mBoundServices.get(j);
service.dump(fd, pw, args);
}
pw.println("}]");
@@ -1462,10 +1431,10 @@
public static final int MSG_SEND_ACCESSIBILITY_EVENT_TO_INPUT_FILTER = 1;
public static final int MSG_SEND_STATE_TO_CLIENTS = 2;
public static final int MSG_SEND_CLEARED_STATE_TO_CLIENTS_FOR_USER = 3;
- public static final int MSG_SEND_RECREATE_INTERNAL_STATE = 4;
- public static final int MSG_UPDATE_ACTIVE_WINDOW = 5;
- public static final int MSG_ANNOUNCE_NEW_USER_IF_NEEDED = 6;
- public static final int MSG_UPDATE_INPUT_FILTER = 7;
+ public static final int MSG_UPDATE_ACTIVE_WINDOW = 4;
+ public static final int MSG_ANNOUNCE_NEW_USER_IF_NEEDED = 5;
+ public static final int MSG_UPDATE_INPUT_FILTER = 6;
+ public static final int MSG_SHOW_ENABLED_TOUCH_EXPLORATION_DIALOG = 7;
public MainHandler(Looper looper) {
super(looper);
@@ -1494,13 +1463,6 @@
final int userId = msg.arg1;
sendStateToClientsForUser(0, userId);
} break;
- case MSG_SEND_RECREATE_INTERNAL_STATE: {
- final int userId = msg.arg1;
- synchronized (mLock) {
- UserState userState = getUserStateLocked(userId);
- recreateInternalStateLocked(userState);
- }
- } break;
case MSG_UPDATE_ACTIVE_WINDOW: {
final int windowId = msg.arg1;
final int eventType = msg.arg2;
@@ -1513,6 +1475,10 @@
UserState userState = (UserState) msg.obj;
updateInputFilter(userState);
} break;
+ case MSG_SHOW_ENABLED_TOUCH_EXPLORATION_DIALOG: {
+ Service service = (Service) msg.obj;
+ showEnableTouchExplorationDialog(service);
+ } break;
}
}
@@ -1641,14 +1607,14 @@
};
public Service(int userId, ComponentName componentName,
- AccessibilityServiceInfo accessibilityServiceInfo, boolean isAutomation) {
+ AccessibilityServiceInfo accessibilityServiceInfo) {
mUserId = userId;
mResolveInfo = accessibilityServiceInfo.getResolveInfo();
mId = sIdCounter++;
mComponentName = componentName;
mAccessibilityServiceInfo = accessibilityServiceInfo;
- mIsAutomation = isAutomation;
- if (!isAutomation) {
+ mIsAutomation = (sFakeAccessibilityServiceComponentName.equals(componentName));
+ if (!mIsAutomation) {
mCanRetrieveScreenContent = accessibilityServiceInfo.getCanRetrieveWindowContent();
mIntent = new Intent().setComponent(mComponentName);
mIntent.putExtra(Intent.EXTRA_CLIENT_LABEL,
@@ -1688,24 +1654,6 @@
mRequestEnhancedWebAccessibility = (info.flags
& AccessibilityServiceInfo.FLAG_REQUEST_ENHANCED_WEB_ACCESSIBILITY) != 0;
}
-
- // If this service is up and running we may have to enable touch
- // exploration or enhanced web accessibility, otherwise this will
- // happen when the service connects.
- synchronized (mLock) {
- if (canReceiveEventsLocked()) {
- if (mRequestTouchExplorationMode) {
- tryEnableTouchExplorationLocked(this);
- } else {
- tryDisableTouchExplorationLocked(this);
- }
- if (mRequestEnhancedWebAccessibility) {
- tryEnableEnhancedWebAccessibilityLocked(this);
- } else {
- tryDisableEnhancedWebAccessibilityLocked(this);
- }
- }
- }
}
/**
@@ -1713,10 +1661,20 @@
*
* @return True if binding is successful.
*/
- public boolean bind() {
- if (!mIsAutomation && mService == null) {
- return mContext.bindServiceAsUser(mIntent, this, Context.BIND_AUTO_CREATE,
- new UserHandle(mUserId));
+ public boolean bindLocked() {
+ UserState userState = getUserStateLocked(mUserId);
+ if (!mIsAutomation) {
+ if (mService == null) {
+ if (mContext.bindServiceAsUser(mIntent, this, Context.BIND_AUTO_CREATE,
+ new UserHandle(mUserId))) {
+ userState.mBindingServices.add(mComponentName);
+ }
+ }
+ } else {
+ userState.mBindingServices.add(mComponentName);
+ mService = userState.mUiAutomationServiceClient.asBinder();
+ onServiceConnected(mComponentName, mService);
+ userState.mUiAutomationService = this;
}
return false;
}
@@ -1727,17 +1685,19 @@
*
* @return True if unbinding is successful.
*/
- public boolean unbind() {
- if (mService != null) {
- synchronized (mLock) {
- tryRemoveServiceLocked(this);
- }
- if (!mIsAutomation) {
- mContext.unbindService(this);
- }
- return true;
+ public boolean unbindLocked() {
+ if (mService == null) {
+ return false;
}
- return false;
+ if (!mIsAutomation) {
+ mContext.unbindService(this);
+ } else {
+ UserState userState = getUserStateLocked(mUserId);
+ userState.mUiAutomationService = null;
+ userState.mUiAutomationServiceClient = null;
+ }
+ removeServiceLocked(this);
+ return true;
}
public boolean canReceiveEventsLocked() {
@@ -1766,6 +1726,8 @@
} else {
setDynamicallyConfigurableProperties(info);
}
+ UserState userState = getUserStateLocked(mUserId);
+ onUserStateChangedLocked(userState);
}
} finally {
Binder.restoreCallingIdentity(identity);
@@ -1774,15 +1736,24 @@
@Override
public void onServiceConnected(ComponentName componentName, IBinder service) {
- mService = service;
- mServiceInterface = IAccessibilityServiceClient.Stub.asInterface(service);
- try {
- mServiceInterface.setConnection(this, mId);
- synchronized (mLock) {
- tryAddServiceLocked(this, mUserId);
+ final int connectionId;
+ synchronized (mLock) {
+ connectionId = mId;
+ mService = service;
+ mServiceInterface = IAccessibilityServiceClient.Stub.asInterface(service);
+ UserState userState = getUserStateLocked(mUserId);
+ if (!userState.mBindingServices.contains(mComponentName)) {
+ binderDied();
+ } else {
+ userState.mBindingServices.remove(mComponentName);
+ addServiceLocked(this, userState);
+ onUserStateChangedLocked(userState);
}
+ }
+ try {
+ mServiceInterface.setConnection(this, connectionId);
} catch (RemoteException re) {
- Slog.w(LOG_TAG, "Error while setting Controller for service: " + service, re);
+ Slog.w(LOG_TAG, "Error while setting connection for service: " + service, re);
}
}
@@ -2128,13 +2099,15 @@
public void binderDied() {
synchronized (mLock) {
// The death recipient is unregistered in tryRemoveServiceLocked
- tryRemoveServiceLocked(this);
- // We no longer have an automation service, so restore
- // the state based on values in the settings database.
+ removeServiceLocked(this);
+ UserState userState = getUserStateLocked(mUserId);
if (mIsAutomation) {
- mUiAutomationService = null;
- recreateInternalStateLocked(getUserStateLocked(mUserId));
+ // We no longer have an automation service, so restore
+ // the state based on values in the settings database.
+ userState.mUiAutomationService = null;
+ userState.mUiAutomationServiceClient = null;
}
+ onUserStateChangedLocked(userState);
}
}
@@ -2585,7 +2558,7 @@
private class UserState {
public final int mUserId;
- public final CopyOnWriteArrayList<Service> mServices = new CopyOnWriteArrayList<Service>();
+ public final CopyOnWriteArrayList<Service> mBoundServices = new CopyOnWriteArrayList<Service>();
public final RemoteCallbackList<IAccessibilityManagerClient> mClients =
new RemoteCallbackList<IAccessibilityManagerClient>();
@@ -2596,6 +2569,8 @@
public final List<AccessibilityServiceInfo> mInstalledServices =
new ArrayList<AccessibilityServiceInfo>();
+ public final Set<ComponentName> mBindingServices = new HashSet<ComponentName>();
+
public final Set<ComponentName> mEnabledServices = new HashSet<ComponentName>();
public final Set<ComponentName> mTouchExplorationGrantedServices =
@@ -2609,57 +2584,30 @@
public int mHandledFeedbackTypes = 0;
+ public int mLastSentClientState;
+
public boolean mIsAccessibilityEnabled;
public boolean mIsTouchExplorationEnabled;
public boolean mIsEnhancedWebAccessibilityEnabled;
public boolean mIsDisplayMagnificationEnabled;
+ private Service mUiAutomationService;
+ private IAccessibilityServiceClient mUiAutomationServiceClient;
+
public UserState(int userId) {
mUserId = userId;
}
- }
- private class TempUserStateChangeMemento {
- public int mUserId = UserHandle.USER_NULL;
- public boolean mIsAccessibilityEnabled;
- public boolean mIsTouchExplorationEnabled;
- public boolean mIsEnhancedWebAccessibilityEnabled;
- public boolean mIsDisplayMagnificationEnabled;
- public final Set<ComponentName> mEnabledServices = new HashSet<ComponentName>();
- public final Set<ComponentName> mTouchExplorationGrantedServices =
- new HashSet<ComponentName>();
-
- public void initialize(UserState userState) {
- mUserId = userState.mUserId;
- mIsAccessibilityEnabled = userState.mIsAccessibilityEnabled;
- mIsTouchExplorationEnabled = userState.mIsTouchExplorationEnabled;
- mIsEnhancedWebAccessibilityEnabled = userState.mIsEnhancedWebAccessibilityEnabled;
- mIsDisplayMagnificationEnabled = userState.mIsDisplayMagnificationEnabled;
- mEnabledServices.clear();
- mEnabledServices.addAll(userState.mEnabledServices);
- mTouchExplorationGrantedServices.clear();
- mTouchExplorationGrantedServices.addAll(userState.mTouchExplorationGrantedServices);
- }
-
- public void applyTo(UserState userState) {
- userState.mIsAccessibilityEnabled = mIsAccessibilityEnabled;
- userState.mIsTouchExplorationEnabled = mIsTouchExplorationEnabled;
- userState.mIsEnhancedWebAccessibilityEnabled = mIsEnhancedWebAccessibilityEnabled;
- userState.mIsDisplayMagnificationEnabled = mIsDisplayMagnificationEnabled;
- userState.mEnabledServices.clear();
- userState.mEnabledServices.addAll(mEnabledServices);
- userState.mTouchExplorationGrantedServices.clear();
- userState.mTouchExplorationGrantedServices.addAll(mTouchExplorationGrantedServices);
- }
-
- public void clear() {
- mUserId = UserHandle.USER_NULL;
- mIsAccessibilityEnabled = false;
- mIsTouchExplorationEnabled = false;
- mIsEnhancedWebAccessibilityEnabled = false;
- mIsDisplayMagnificationEnabled = false;
- mEnabledServices.clear();
- mTouchExplorationGrantedServices.clear();
+ public int getClientState() {
+ int clientState = 0;
+ if (mIsAccessibilityEnabled) {
+ clientState |= AccessibilityManager.STATE_FLAG_ACCESSIBILITY_ENABLED;
+ }
+ // Touch exploration relies on enabled accessibility.
+ if (mIsAccessibilityEnabled && mIsTouchExplorationEnabled) {
+ clientState |= AccessibilityManager.STATE_FLAG_TOUCH_EXPLORATION_ENABLED;
+ }
+ return clientState;
}
}
@@ -2680,7 +2628,7 @@
private final Uri mTouchExplorationGrantedAccessibilityServicesUri = Settings.Secure
.getUriFor(Settings.Secure.TOUCH_EXPLORATION_GRANTED_ACCESSIBILITY_SERVICES);
- private final Uri mAccessibilityScriptInjectionUri = Settings.Secure
+ private final Uri mEnhancedWebAccessibilityUri = Settings.Secure
.getUriFor(Settings.Secure.ACCESSIBILITY_SCRIPT_INJECTION);
public AccessibilityContentObserver(Handler handler) {
@@ -2699,7 +2647,7 @@
contentResolver.registerContentObserver(
mTouchExplorationGrantedAccessibilityServicesUri,
false, this, UserHandle.USER_ALL);
- contentResolver.registerContentObserver(mAccessibilityScriptInjectionUri,
+ contentResolver.registerContentObserver(mEnhancedWebAccessibilityUri,
false, this, UserHandle.USER_ALL);
}
@@ -2708,58 +2656,61 @@
if (mAccessibilityEnabledUri.equals(uri)) {
synchronized (mLock) {
// We will update when the automation service dies.
- if (mUiAutomationService == null) {
- UserState userState = getCurrentUserStateLocked();
- handleAccessibilityEnabledSettingChangedLocked(userState);
- performServiceManagementLocked(userState);
- scheduleUpdateInputFilter(userState);
- scheduleSendStateToClientsLocked(userState);
+ UserState userState = getCurrentUserStateLocked();
+ if (userState.mUiAutomationService == null) {
+ if (readAccessibilityEnabledSettingLocked(userState)) {
+ onUserStateChangedLocked(userState);
+ }
}
}
} else if (mTouchExplorationEnabledUri.equals(uri)) {
synchronized (mLock) {
// We will update when the automation service dies.
- if (mUiAutomationService == null) {
- UserState userState = getCurrentUserStateLocked();
- handleTouchExplorationEnabledSettingChangedLocked(userState);
- scheduleUpdateInputFilter(userState);
- scheduleSendStateToClientsLocked(userState);
+ UserState userState = getCurrentUserStateLocked();
+ if (userState.mUiAutomationService == null) {
+ if (readTouchExplorationEnabledSettingLocked(userState)) {
+ onUserStateChangedLocked(userState);
+ }
}
}
} else if (mDisplayMagnificationEnabledUri.equals(uri)) {
synchronized (mLock) {
// We will update when the automation service dies.
- if (mUiAutomationService == null) {
- UserState userState = getCurrentUserStateLocked();
- handleDisplayMagnificationEnabledSettingChangedLocked(userState);
- scheduleUpdateInputFilter(userState);
- scheduleSendStateToClientsLocked(userState);
+ UserState userState = getCurrentUserStateLocked();
+ if (userState.mUiAutomationService == null) {
+ if (readDisplayMagnificationEnabledSettingLocked(userState)) {
+ onUserStateChangedLocked(userState);
+ }
}
}
} else if (mEnabledAccessibilityServicesUri.equals(uri)) {
synchronized (mLock) {
// We will update when the automation service dies.
- if (mUiAutomationService == null) {
- UserState userState = getCurrentUserStateLocked();
- populateEnabledAccessibilityServicesLocked(userState);
- manageServicesLocked(userState);
+ UserState userState = getCurrentUserStateLocked();
+ if (userState.mUiAutomationService == null) {
+ if (readEnabledAccessibilityServicesLocked(userState)) {
+ onUserStateChangedLocked(userState);
+ }
}
}
} else if (mTouchExplorationGrantedAccessibilityServicesUri.equals(uri)) {
synchronized (mLock) {
// We will update when the automation service dies.
- if (mUiAutomationService == null) {
- UserState userState = getCurrentUserStateLocked();
- populateTouchExplorationGrantedAccessibilityServicesLocked(userState);
- handleTouchExplorationGrantedAccessibilityServicesChangedLocked(userState);
+ UserState userState = getCurrentUserStateLocked();
+ if (userState.mUiAutomationService == null) {
+ if (readTouchExplorationGrantedAccessibilityServicesLocked(userState)) {
+ onUserStateChangedLocked(userState);
+ }
}
}
- } else if (mAccessibilityScriptInjectionUri.equals(uri)) {
+ } else if (mEnhancedWebAccessibilityUri.equals(uri)) {
synchronized (mLock) {
// We will update when the automation service dies.
- if (mUiAutomationService == null) {
- UserState userState = getCurrentUserStateLocked();
- populatedEnhancedWebAccessibilityEnabledChangedLocked(userState);
+ UserState userState = getCurrentUserStateLocked();
+ if (userState.mUiAutomationService == null) {
+ if (readEnhancedWebAccessibilityEnabledChangedLocked(userState)) {
+ onUserStateChangedLocked(userState);
+ }
}
}
}
diff --git a/services/java/com/android/server/accounts/AccountManagerService.java b/services/java/com/android/server/accounts/AccountManagerService.java
index 88603dc..2a62c17 100644
--- a/services/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/java/com/android/server/accounts/AccountManagerService.java
@@ -21,6 +21,7 @@
import android.accounts.AccountAndUser;
import android.accounts.AccountAuthenticatorResponse;
import android.accounts.AccountManager;
+import android.accounts.AccountManagerResponse;
import android.accounts.AuthenticatorDescription;
import android.accounts.GrantCredentialsPermissionActivity;
import android.accounts.IAccountAuthenticator;
@@ -526,6 +527,9 @@
}
if (account == null) throw new IllegalArgumentException("account is null");
checkAuthenticateAccountsPermission(account);
+ if (!canUserModifyAccounts(Binder.getCallingUid())) {
+ return false;
+ }
UserAccounts accounts = getUserAccountsForCaller();
// fails if the account already exists
@@ -679,6 +683,14 @@
checkManageAccountsPermission();
UserHandle user = Binder.getCallingUserHandle();
UserAccounts accounts = getUserAccountsForCaller();
+ if (!canUserModifyAccounts(Binder.getCallingUid())) {
+ try {
+ response.onError(AccountManager.ERROR_CODE_UNSUPPORTED_OPERATION,
+ "User cannot modify accounts");
+ } catch (RemoteException re) {
+ }
+ }
+
long identityToken = clearCallingIdentity();
cancelNotification(getSigninRequiredNotificationId(accounts, account), user);
@@ -2312,6 +2324,17 @@
Manifest.permission.USE_CREDENTIALS);
}
+ private boolean canUserModifyAccounts(int callingUid) {
+ if (callingUid != android.os.Process.myUid()) {
+ Bundle restrictions = getUserManager().getUserRestrictions(
+ new UserHandle(UserHandle.getUserId(callingUid)));
+ if (!restrictions.getBoolean(UserManager.ALLOW_MODIFY_ACCOUNTS)) {
+ return false;
+ }
+ }
+ return true;
+ }
+
public void updateAppPermission(Account account, String authTokenType, int uid, boolean value)
throws RemoteException {
final int callingUid = getCallingUid();
diff --git a/services/java/com/android/server/am/ActivityManagerService.java b/services/java/com/android/server/am/ActivityManagerService.java
index 7b6e79e..608ad1c 100644
--- a/services/java/com/android/server/am/ActivityManagerService.java
+++ b/services/java/com/android/server/am/ActivityManagerService.java
@@ -37,6 +37,7 @@
import android.app.Activity;
import android.app.ActivityManager;
+import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityManagerNative;
import android.app.ActivityOptions;
import android.app.ActivityThread;
@@ -328,7 +329,7 @@
/**
* List of intents that were used to start the most recent tasks.
*/
- final ArrayList<TaskRecord> mRecentTasks = new ArrayList<TaskRecord>();
+ private final ArrayList<TaskRecord> mRecentTasks = new ArrayList<TaskRecord>();
public class PendingActivityExtras extends Binder implements Runnable {
public final ActivityRecord activity;
@@ -596,13 +597,8 @@
* List of PendingThumbnailsRecord objects of clients who are still
* waiting to receive all of the thumbnails for a task.
*/
- final ArrayList mPendingThumbnails = new ArrayList();
-
- /**
- * List of HistoryRecord objects that have been finished and must
- * still report back to a pending thumbnail receiver.
- */
- final ArrayList mCancelledThumbnails = new ArrayList();
+ final ArrayList<PendingThumbnailsRecord> mPendingThumbnails =
+ new ArrayList<PendingThumbnailsRecord>();
final ProviderMap mProviderMap;
@@ -2932,22 +2928,13 @@
}
}
+ @Override
public boolean willActivityBeVisible(IBinder token) {
synchronized(this) {
- int i;
- for (i=mMainStack.mHistory.size()-1; i>=0; i--) {
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
- if (r.appToken == token) {
- return true;
- }
- if (r.fullscreen && !r.finishing) {
- return false;
- }
- }
- return true;
+ return mMainStack.willActivityBeVisibleLocked(token);
}
}
-
+
public void overridePendingTransition(IBinder token, String packageName,
int enterAnim, int exitAnim) {
synchronized(this) {
@@ -3717,13 +3704,7 @@
}
mWindowManager.closeSystemDialogs(reason);
- for (int i=mMainStack.mHistory.size()-1; i>=0; i--) {
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
- if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
- r.stack.finishActivityLocked(r, i,
- Activity.RESULT_CANCELED, null, "close-sys", true);
- }
- }
+ mMainStack.closeSystemDialogsLocked();
broadcastIntentLocked(null, null, intent, null,
null, 0, null, null, null, AppOpsManager.OP_NONE, false, false, -1,
@@ -3930,37 +3911,12 @@
boolean didSomething = killPackageProcessesLocked(name, appId, userId,
-100, callerWillRestart, true, doit, evenPersistent,
name == null ? ("force stop user " + userId) : ("force stop " + name));
-
- TaskRecord lastTask = null;
- for (i=0; i<mMainStack.mHistory.size(); i++) {
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
- final boolean samePackage = r.packageName.equals(name)
- || (name == null && r.userId == userId);
- if ((userId == UserHandle.USER_ALL || r.userId == userId)
- && (samePackage || r.task == lastTask)
- && (r.app == null || evenPersistent || !r.app.persistent)) {
- if (!doit) {
- if (r.finishing) {
- // If this activity is just finishing, then it is not
- // interesting as far as something to stop.
- continue;
- }
- return true;
- }
- didSomething = true;
- Slog.i(TAG, " Force finishing activity " + r);
- if (samePackage) {
- if (r.app != null) {
- r.app.removed = true;
- }
- r.app = null;
- }
- lastTask = r.task;
- if (r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED,
- null, "force-stop", true)) {
- i--;
- }
+
+ if (mMainStack.forceStopPackageLocked(name, doit, evenPersistent, userId)) {
+ if (!doit) {
+ return true;
}
+ didSomething = true;
}
if (mServices.forceStopLocked(name, userId, evenPersistent, doit)) {
@@ -5670,12 +5626,12 @@
// TASK MANAGEMENT
// =========================================================
- public List getTasks(int maxNum, int flags,
+ @Override
+ public List<RunningTaskInfo> getTasks(int maxNum, int flags,
IThumbnailReceiver receiver) {
- ArrayList list = new ArrayList();
+ ArrayList<RunningTaskInfo> list = new ArrayList<RunningTaskInfo>();
- PendingThumbnailsRecord pending = null;
- IApplicationThread topThumbnail = null;
+ PendingThumbnailsRecord pending = new PendingThumbnailsRecord(receiver);
ActivityRecord topRecord = null;
synchronized(this) {
@@ -5701,88 +5657,19 @@
throw new SecurityException(msg);
}
- int pos = mMainStack.mHistory.size()-1;
- ActivityRecord next =
- pos >= 0 ? (ActivityRecord)mMainStack.mHistory.get(pos) : null;
- ActivityRecord top = null;
- TaskRecord curTask = null;
- int numActivities = 0;
- int numRunning = 0;
- while (pos >= 0 && maxNum > 0) {
- final ActivityRecord r = next;
- pos--;
- next = pos >= 0 ? (ActivityRecord)mMainStack.mHistory.get(pos) : null;
+ topRecord = mMainStack.getTasksLocked(maxNum, receiver, pending, list);
- // Initialize state for next task if needed.
- if (top == null ||
- (top.state == ActivityState.INITIALIZING
- && top.task == r.task)) {
- top = r;
- curTask = r.task;
- numActivities = numRunning = 0;
- }
-
- // Add 'r' into the current task.
- numActivities++;
- if (r.app != null && r.app.thread != null) {
- numRunning++;
- }
-
- if (localLOGV) Slog.v(
- TAG, r.intent.getComponent().flattenToShortString()
- + ": task=" + r.task);
-
- // If the next one is a different task, generate a new
- // TaskInfo entry for what we have.
- if (next == null || next.task != curTask) {
- ActivityManager.RunningTaskInfo ci
- = new ActivityManager.RunningTaskInfo();
- ci.id = curTask.taskId;
- ci.baseActivity = r.intent.getComponent();
- ci.topActivity = top.intent.getComponent();
- if (top.thumbHolder != null) {
- ci.description = top.thumbHolder.lastDescription;
- }
- ci.numActivities = numActivities;
- ci.numRunning = numRunning;
- //System.out.println(
- // "#" + maxNum + ": " + " descr=" + ci.description);
- if (ci.thumbnail == null && receiver != null) {
- if (localLOGV) Slog.v(
- TAG, "State=" + top.state + "Idle=" + top.idle
- + " app=" + top.app
- + " thr=" + (top.app != null ? top.app.thread : null));
- if (top.state == ActivityState.RESUMED
- || top.state == ActivityState.PAUSING) {
- if (top.idle && top.app != null
- && top.app.thread != null) {
- topRecord = top;
- topThumbnail = top.app.thread;
- } else {
- top.thumbnailNeeded = true;
- }
- }
- if (pending == null) {
- pending = new PendingThumbnailsRecord(receiver);
- }
- pending.pendingRecords.add(top);
- }
- list.add(ci);
- maxNum--;
- top = null;
- }
- }
-
- if (pending != null) {
+ if (!pending.pendingRecords.isEmpty()) {
mPendingThumbnails.add(pending);
}
}
if (localLOGV) Slog.v(TAG, "We have pending thumbnails: " + pending);
- if (topThumbnail != null) {
+ if (topRecord != null) {
if (localLOGV) Slog.v(TAG, "Requesting top thumbnail");
try {
+ IApplicationThread topThumbnail = topRecord.app.thread;
topThumbnail.requestThumbnail(topRecord.appToken);
} catch (Exception e) {
Slog.w(TAG, "Exception thrown when requesting thumbnail", e);
@@ -6017,43 +5904,6 @@
return false;
}
- private final int findAffinityTaskTopLocked(int startIndex, String affinity) {
- int j;
- TaskRecord startTask = ((ActivityRecord)mMainStack.mHistory.get(startIndex)).task;
- TaskRecord jt = startTask;
-
- // First look backwards
- for (j=startIndex-1; j>=0; j--) {
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(j);
- if (r.task != jt) {
- jt = r.task;
- if (affinity.equals(jt.affinity)) {
- return j;
- }
- }
- }
-
- // Now look forwards
- final int N = mMainStack.mHistory.size();
- jt = startTask;
- for (j=startIndex+1; j<N; j++) {
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(j);
- if (r.task != jt) {
- if (affinity.equals(jt.affinity)) {
- return j;
- }
- jt = r.task;
- }
- }
-
- // Might it be at the top?
- if (affinity.equals(((ActivityRecord)mMainStack.mHistory.get(N-1)).task.affinity)) {
- return N-1;
- }
-
- return -1;
- }
-
/**
* TODO: Add mController hook
*/
@@ -6082,20 +5932,8 @@
mMainStack.moveTaskToFrontLocked(tr, null, options);
return;
}
- for (int i=mMainStack.mHistory.size()-1; i>=0; i--) {
- ActivityRecord hr = (ActivityRecord)mMainStack.mHistory.get(i);
- if (hr.task.taskId == task) {
- if ((flags&ActivityManager.MOVE_TASK_NO_USER_ACTION) == 0) {
- mMainStack.mUserLeaving = true;
- }
- if ((flags&ActivityManager.MOVE_TASK_WITH_HOME) != 0) {
- // Caller wants the home activity moved with it. To accomplish this,
- // we'll just move the home task to the top first.
- mMainStack.moveHomeToFrontLocked();
- }
- mMainStack.moveTaskToFrontLocked(hr.task, null, options);
- return;
- }
+ if (mMainStack.findTaskToMoveToFrontLocked(task, flags, options)) {
+ return;
}
} finally {
Binder.restoreCallingIdentity(origId);
@@ -6135,7 +5973,7 @@
enforceNotIsolatedCaller("moveActivityTaskToBack");
synchronized(this) {
final long origId = Binder.clearCallingIdentity();
- int taskId = getTaskForActivityLocked(token, !nonRoot);
+ int taskId = mMainStack.getTaskForActivityLocked(token, !nonRoot);
if (taskId >= 0) {
return mMainStack.moveTaskToBackLocked(taskId, null);
}
@@ -6165,27 +6003,10 @@
public int getTaskForActivity(IBinder token, boolean onlyRoot) {
synchronized(this) {
- return getTaskForActivityLocked(token, onlyRoot);
+ return mMainStack.getTaskForActivityLocked(token, onlyRoot);
}
}
- int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
- final int N = mMainStack.mHistory.size();
- TaskRecord lastTask = null;
- for (int i=0; i<N; i++) {
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
- if (r.appToken == token) {
- if (!onlyRoot || lastTask != r.task) {
- return r.task.taskId;
- }
- return -1;
- }
- lastTask = r.task;
- }
-
- return -1;
- }
-
// =========================================================
// THUMBNAILS
// =========================================================
@@ -7091,13 +6912,10 @@
"unhandledBack()");
synchronized(this) {
- int count = mMainStack.mHistory.size();
- if (DEBUG_SWITCH) Slog.d(
- TAG, "Performing unhandledBack(): stack size = " + count);
- if (count > 1) {
- final long origId = Binder.clearCallingIdentity();
- mMainStack.finishActivityLocked((ActivityRecord)mMainStack.mHistory.get(count-1),
- count-1, Activity.RESULT_CANCELED, null, "unhandled-back", true);
+ final long origId = Binder.clearCallingIdentity();
+ try {
+ mMainStack.unhandledBackLocked();
+ } finally {
Binder.restoreCallingIdentity(origId);
}
}
@@ -7925,7 +7743,8 @@
}
mDidUpdate = true;
}
-
+
+ mAppOpsService.systemReady();
mSystemReady = true;
if (!mStartRunning) {
return;
@@ -8158,15 +7977,7 @@
+ " has crashed too many times: killing!");
EventLog.writeEvent(EventLogTags.AM_PROCESS_CRASHED_TOO_MUCH,
app.userId, app.info.processName, app.uid);
- for (int i=mMainStack.mHistory.size()-1; i>=0; i--) {
- ActivityRecord r = (ActivityRecord)mMainStack.mHistory.get(i);
- if (r.app == app) {
- Slog.w(TAG, " Force finishing activity "
- + r.intent.getComponent().flattenToShortString());
- r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED,
- null, "crashed", false);
- }
- }
+ mMainStack.handleAppCrashLocked(app);
if (!app.persistent) {
// We don't want to start this process again until the user
// explicitly does so... but for persistent process, we really
@@ -8205,7 +8016,7 @@
// re-start our crashing activity once it gets resumed again.
index--;
if (index >= 0) {
- r = (ActivityRecord)mMainStack.mHistory.get(index);
+ r = mMainStack.getActivityAtIndex(index);
if (r.state == ActivityState.RESUMED
|| r.state == ActivityState.PAUSING
|| r.state == ActivityState.PAUSED) {
@@ -9236,8 +9047,7 @@
int opti, boolean dumpAll, boolean dumpClient, String dumpPackage) {
pw.println("ACTIVITY MANAGER ACTIVITIES (dumpsys activity activities)");
pw.println(" Main stack:");
- dumpHistoryList(fd, pw, mMainStack.mHistory, " ", "Hist", true, !dumpAll, dumpClient,
- dumpPackage);
+ mMainStack.dumpActivitiesLocked(fd, pw, dumpAll, dumpClient, dumpPackage);
pw.println(" ");
pw.println(" Running activities (most recent first):");
dumpHistoryList(fd, pw, mMainStack.mLRUActivities, " ", "Run", false, !dumpAll, false,
@@ -9767,32 +9577,10 @@
*/
protected boolean dumpActivity(FileDescriptor fd, PrintWriter pw, String name, String[] args,
int opti, boolean dumpAll) {
- ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>();
-
- if ("all".equals(name)) {
- synchronized (this) {
- for (ActivityRecord r1 : (ArrayList<ActivityRecord>)mMainStack.mHistory) {
- activities.add(r1);
- }
- }
- } else if ("top".equals(name)) {
- synchronized (this) {
- final int N = mMainStack.mHistory.size();
- if (N > 0) {
- activities.add((ActivityRecord)mMainStack.mHistory.get(N-1));
- }
- }
- } else {
- ItemMatcher matcher = new ItemMatcher();
- matcher.build(name);
-
- synchronized (this) {
- for (ActivityRecord r1 : (ArrayList<ActivityRecord>)mMainStack.mHistory) {
- if (matcher.match(r1, r1.intent.getComponent())) {
- activities.add(r1);
- }
- }
- }
+ ArrayList<ActivityRecord> activities;
+
+ synchronized (this) {
+ activities = mMainStack.getDumpActivitiesLocked(name);
}
if (activities.size() <= 0) {
@@ -10044,7 +9832,7 @@
return needSep;
}
- private static final void dumpHistoryList(FileDescriptor fd, PrintWriter pw, List list,
+ static final void dumpHistoryList(FileDescriptor fd, PrintWriter pw, List list,
String prefix, String label, boolean complete, boolean brief, boolean client,
String dumpPackage) {
TaskRecord lastTask = null;
@@ -11779,6 +11567,7 @@
synchronized (bs) {
bs.removeUidStatsLocked(uid);
}
+ mAppOpsService.uidRemoved(uid);
}
} else {
// If resources are unavailable just force stop all
@@ -11804,6 +11593,10 @@
if (Intent.ACTION_PACKAGE_REMOVED.equals(intent.getAction())) {
sendPackageBroadcastLocked(IApplicationThread.PACKAGE_REMOVED,
new String[] {ssp}, userId);
+ if (!intent.getBooleanExtra(Intent.EXTRA_REPLACING, false)) {
+ mAppOpsService.packageRemoved(
+ intent.getIntExtra(Intent.EXTRA_UID, -1), ssp);
+ }
}
}
}
@@ -12584,8 +12377,8 @@
if (srec == null) {
return false;
}
- ArrayList<ActivityRecord> history = srec.stack.mHistory;
- final int start = history.indexOf(srec);
+ ActivityStack stack = srec.stack;
+ final int start = stack.indexOfActivityLocked(srec);
if (start < 0) {
// Current activity is not in history stack; do nothing.
return false;
@@ -12596,13 +12389,13 @@
if (dest != null) {
TaskRecord tr = srec.task;
for (int i = start - 1; i >= 0; i--) {
- ActivityRecord r = history.get(i);
+ ActivityRecord r = stack.getActivityAtIndex(i);
if (tr != r.task) {
// Couldn't find parent in the same task; stop at the one above this.
// (Root of current task; in-app "home" behavior)
// Always at least finish the current activity.
finishTo = Math.min(start - 1, i + 1);
- parent = history.get(finishTo);
+ parent = stack.getActivityAtIndex(finishTo);
break;
} else if (r.info.packageName.equals(dest.getPackageName()) &&
r.info.name.equals(dest.getClassName())) {
@@ -12632,7 +12425,7 @@
}
final long origId = Binder.clearCallingIdentity();
for (int i = start; i > finishTo; i--) {
- ActivityRecord r = history.get(i);
+ ActivityRecord r = stack.getActivityAtIndex(i);
mMainStack.requestFinishActivityLocked(r.appToken, resultCode, resultData,
"navigate-up", true);
// Only return the supplied result for the first activity finished
diff --git a/services/java/com/android/server/am/ActivityRecord.java b/services/java/com/android/server/am/ActivityRecord.java
index ba2e47a..cde17c9 100644
--- a/services/java/com/android/server/am/ActivityRecord.java
+++ b/services/java/com/android/server/am/ActivityRecord.java
@@ -574,6 +574,9 @@
*/
final void deliverNewIntentLocked(int callingUid, Intent intent) {
boolean sent = false;
+ // The activity now gets access to the data associated with this Intent.
+ service.grantUriPermissionFromIntentLocked(callingUid, packageName,
+ intent, getUriPermissionsLocked());
// We want to immediately deliver the intent to the activity if
// it is currently the top resumed activity... however, if the
// device is sleeping, then all activities are stopped, so in that
@@ -586,8 +589,6 @@
ArrayList<Intent> ar = new ArrayList<Intent>();
intent = new Intent(intent);
ar.add(intent);
- service.grantUriPermissionFromIntentLocked(callingUid, packageName,
- intent, getUriPermissionsLocked());
app.thread.scheduleNewIntent(ar, appToken);
sent = true;
} catch (RemoteException e) {
diff --git a/services/java/com/android/server/am/ActivityStack.java b/services/java/com/android/server/am/ActivityStack.java
index e164d0e..d969709 100644
--- a/services/java/com/android/server/am/ActivityStack.java
+++ b/services/java/com/android/server/am/ActivityStack.java
@@ -21,8 +21,8 @@
import com.android.internal.app.HeavyWeightSwitcherActivity;
import com.android.internal.os.BatteryStatsImpl;
+import com.android.server.am.ActivityManagerService.ItemMatcher;
import com.android.server.am.ActivityManagerService.PendingActivityLaunch;
-import com.android.server.am.ActivityRecord.Token;
import com.android.server.wm.AppTransition;
import android.app.Activity;
@@ -30,10 +30,12 @@
import android.app.ActivityOptions;
import android.app.AppGlobals;
import android.app.IActivityManager;
+import android.app.IThumbnailReceiver;
import android.app.IThumbnailRetriever;
import android.app.IApplicationThread;
import android.app.PendingIntent;
import android.app.ResultInfo;
+import android.app.ActivityManager.RunningTaskInfo;
import android.app.IActivityManager.WaitResult;
import android.content.ComponentName;
import android.content.Context;
@@ -64,7 +66,9 @@
import android.util.Slog;
import android.view.Display;
+import java.io.FileDescriptor;
import java.io.IOException;
+import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.ArrayList;
import java.util.Iterator;
@@ -151,9 +155,9 @@
/**
* The back history of all previous (and possibly still
- * running) activities. It contains HistoryRecord objects.
+ * running) activities. It contains #ActivityRecord objects.
*/
- final ArrayList<ActivityRecord> mHistory = new ArrayList<ActivityRecord>();
+ private final ArrayList<ActivityRecord> mHistory = new ArrayList<ActivityRecord>();
/**
* Used for validating app tokens with window manager.
@@ -290,6 +294,12 @@
private ActivityRecord mLastScreenshotActivity = null;
private Bitmap mLastScreenshotBitmap = null;
+ /**
+ * List of ActivityRecord objects that have been finished and must
+ * still report back to a pending thumbnail receiver.
+ */
+ private final ArrayList<ActivityRecord> mCancelledThumbnails = new ArrayList<ActivityRecord>();
+
int mThumbnailWidth = -1;
int mThumbnailHeight = -1;
@@ -507,6 +517,31 @@
return null;
}
+ // TODO: This exposes mHistory too much, replace usage with ActivityStack methods.
+ final ActivityRecord getActivityAtIndex(int index) {
+ if (index >= 0 && index < mHistory.size()) {
+ return mHistory.get(index);
+ }
+ return null;
+ }
+
+ int getTaskForActivityLocked(IBinder token, boolean onlyRoot) {
+ TaskRecord lastTask = null;
+ final int N = mHistory.size();
+ for (int i = 0; i < N; i++) {
+ ActivityRecord r = mHistory.get(i);
+ if (r.appToken == token) {
+ if (!onlyRoot || lastTask != r.task) {
+ return r.task.taskId;
+ }
+ return -1;
+ }
+ lastTask = r.task;
+ }
+
+ return -1;
+ }
+
private final boolean updateLRUListLocked(ActivityRecord r) {
final boolean hadit = mLRUActivities.remove(r);
mLRUActivities.add(r);
@@ -3589,9 +3624,9 @@
finishes = new ArrayList<ActivityRecord>(mFinishingActivities);
mFinishingActivities.clear();
}
- if ((NT=mService.mCancelledThumbnails.size()) > 0) {
- thumbnails = new ArrayList<ActivityRecord>(mService.mCancelledThumbnails);
- mService.mCancelledThumbnails.clear();
+ if ((NT=mCancelledThumbnails.size()) > 0) {
+ thumbnails = new ArrayList<ActivityRecord>(mCancelledThumbnails);
+ mCancelledThumbnails.clear();
}
if (mMainStack) {
@@ -3814,7 +3849,7 @@
// There are clients waiting to receive thumbnails so, in case
// this is an activity that someone is waiting for, add it
// to the pending list so we can correctly update the clients.
- mService.mCancelledThumbnails.add(r);
+ mCancelledThumbnails.add(r);
}
if (immediate) {
@@ -3974,7 +4009,7 @@
// There are clients waiting to receive thumbnails so, in case
// this is an activity that someone is waiting for, add it
// to the pending list so we can correctly update the clients.
- mService.mCancelledThumbnails.add(r);
+ mCancelledThumbnails.add(r);
}
// Get rid of any pending idle timeouts.
@@ -4322,6 +4357,25 @@
mService.mWindowManager.prepareAppTransition(transit, false);
}
+ final boolean findTaskToMoveToFrontLocked(int taskId, int flags, Bundle options) {
+ for (int i = mHistory.size() - 1; i >= 0; i--) {
+ ActivityRecord hr = mHistory.get(i);
+ if (hr.task.taskId == taskId) {
+ if ((flags & ActivityManager.MOVE_TASK_NO_USER_ACTION) == 0) {
+ mUserLeaving = true;
+ }
+ if ((flags & ActivityManager.MOVE_TASK_WITH_HOME) != 0) {
+ // Caller wants the home activity moved with it. To accomplish this,
+ // we'll just move the home task to the top first.
+ moveHomeToFrontLocked();
+ }
+ moveTaskToFrontLocked(hr.task, null, options);
+ return true;
+ }
+ }
+ return false;
+ }
+
final void moveTaskToFrontLocked(TaskRecord tr, ActivityRecord reason, Bundle options) {
if (DEBUG_SWITCH) Slog.v(TAG, "moveTaskToFront: " + tr);
@@ -4787,4 +4841,204 @@
public void dismissKeyguardOnNextActivityLocked() {
mDismissKeyguardOnNextActivity = true;
}
+
+ boolean willActivityBeVisibleLocked(IBinder token) {
+ int i;
+ for (i = mHistory.size() - 1; i >= 0; i--) {
+ ActivityRecord r = mHistory.get(i);
+ if (r.appToken == token) {
+ return true;
+ }
+ if (r.fullscreen && !r.finishing) {
+ return false;
+ }
+ }
+ return true;
+ }
+
+ void closeSystemDialogsLocked() {
+ for (int i = mHistory.size() - 1; i >= 0; i--) {
+ ActivityRecord r = mHistory.get(i);
+ if ((r.info.flags&ActivityInfo.FLAG_FINISH_ON_CLOSE_SYSTEM_DIALOGS) != 0) {
+ r.stack.finishActivityLocked(r, i,
+ Activity.RESULT_CANCELED, null, "close-sys", true);
+ }
+ }
+ }
+
+ boolean forceStopPackageLocked(String name, boolean doit, boolean evenPersistent, int userId) {
+ boolean didSomething = false;
+ TaskRecord lastTask = null;
+ final int N = mHistory.size();
+ for (int i = 0; i < N; i++) {
+ ActivityRecord r = mHistory.get(i);
+ final boolean samePackage = r.packageName.equals(name)
+ || (name == null && r.userId == userId);
+ if ((userId == UserHandle.USER_ALL || r.userId == userId)
+ && (samePackage || r.task == lastTask)
+ && (r.app == null || evenPersistent || !r.app.persistent)) {
+ if (!doit) {
+ if (r.finishing) {
+ // If this activity is just finishing, then it is not
+ // interesting as far as something to stop.
+ continue;
+ }
+ return true;
+ }
+ didSomething = true;
+ Slog.i(TAG, " Force finishing activity " + r);
+ if (samePackage) {
+ if (r.app != null) {
+ r.app.removed = true;
+ }
+ r.app = null;
+ }
+ lastTask = r.task;
+ if (r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED,
+ null, "force-stop", true)) {
+ i--;
+ }
+ }
+ }
+ return didSomething;
+ }
+
+ ActivityRecord getTasksLocked(int maxNum, IThumbnailReceiver receiver,
+ PendingThumbnailsRecord pending, List<RunningTaskInfo> list) {
+ ActivityRecord topRecord = null;
+ int pos = mHistory.size() - 1;
+ ActivityRecord next = pos >= 0 ? mHistory.get(pos) : null;
+ ActivityRecord top = null;
+ TaskRecord curTask = null;
+ int numActivities = 0;
+ int numRunning = 0;
+ while (pos >= 0 && maxNum > 0) {
+ final ActivityRecord r = next;
+ pos--;
+ next = pos >= 0 ? mHistory.get(pos) : null;
+
+ // Initialize state for next task if needed.
+ if (top == null || (top.state == ActivityState.INITIALIZING && top.task == r.task)) {
+ top = r;
+ curTask = r.task;
+ numActivities = numRunning = 0;
+ }
+
+ // Add 'r' into the current task.
+ numActivities++;
+ if (r.app != null && r.app.thread != null) {
+ numRunning++;
+ }
+
+ if (localLOGV) Slog.v(
+ TAG, r.intent.getComponent().flattenToShortString()
+ + ": task=" + r.task);
+
+ // If the next one is a different task, generate a new
+ // TaskInfo entry for what we have.
+ if (next == null || next.task != curTask) {
+ RunningTaskInfo ci = new RunningTaskInfo();
+ ci.id = curTask.taskId;
+ ci.baseActivity = r.intent.getComponent();
+ ci.topActivity = top.intent.getComponent();
+ if (top.thumbHolder != null) {
+ ci.description = top.thumbHolder.lastDescription;
+ }
+ ci.numActivities = numActivities;
+ ci.numRunning = numRunning;
+ //System.out.println(
+ // "#" + maxNum + ": " + " descr=" + ci.description);
+ if (receiver != null) {
+ if (localLOGV) Slog.v(
+ TAG, "State=" + top.state + "Idle=" + top.idle
+ + " app=" + top.app
+ + " thr=" + (top.app != null ? top.app.thread : null));
+ if (top.state == ActivityState.RESUMED || top.state == ActivityState.PAUSING) {
+ if (top.idle && top.app != null && top.app.thread != null) {
+ topRecord = top;
+ } else {
+ top.thumbnailNeeded = true;
+ }
+ }
+ pending.pendingRecords.add(top);
+ }
+ list.add(ci);
+ maxNum--;
+ top = null;
+ }
+ }
+ return topRecord;
+ }
+
+ public void unhandledBackLocked() {
+ int top = mHistory.size() - 1;
+ if (DEBUG_SWITCH) Slog.d(
+ TAG, "Performing unhandledBack(): top activity at " + top);
+ if (top > 0) {
+ finishActivityLocked(mHistory.get(top),
+ top, Activity.RESULT_CANCELED, null, "unhandled-back", true);
+ }
+ }
+
+ void handleAppCrashLocked(ProcessRecord app) {
+ for (int i = mHistory.size() - 1; i >= 0; i--) {
+ ActivityRecord r = mHistory.get(i);
+ if (r.app == app) {
+ Slog.w(TAG, " Force finishing activity "
+ + r.intent.getComponent().flattenToShortString());
+ r.stack.finishActivityLocked(r, i, Activity.RESULT_CANCELED,
+ null, "crashed", false);
+ }
+ }
+ }
+
+ void dumpActivitiesLocked(FileDescriptor fd, PrintWriter pw, boolean dumpAll,
+ boolean dumpClient, String dumpPackage) {
+ ActivityManagerService.dumpHistoryList(fd, pw, mHistory, " ", "Hist", true, !dumpAll,
+ dumpClient, dumpPackage);
+ }
+
+ ArrayList<ActivityRecord> getDumpActivitiesLocked(String name) {
+ ArrayList<ActivityRecord> activities = new ArrayList<ActivityRecord>();
+
+ if ("all".equals(name)) {
+ for (ActivityRecord r1 : mHistory) {
+ activities.add(r1);
+ }
+ } else if ("top".equals(name)) {
+ final int N = mHistory.size();
+ if (N > 0) {
+ activities.add(mHistory.get(N-1));
+ }
+ } else {
+ ItemMatcher matcher = new ItemMatcher();
+ matcher.build(name);
+
+ for (ActivityRecord r1 : mHistory) {
+ if (matcher.match(r1, r1.intent.getComponent())) {
+ activities.add(r1);
+ }
+ }
+ }
+
+ return activities;
+ }
+
+ ActivityRecord restartPackage(String packageName) {
+ ActivityRecord starting = topRunningActivityLocked(null);
+
+ // All activities that came from the package must be
+ // restarted as if there was a config change.
+ for (int i = mHistory.size() - 1; i >= 0; i--) {
+ ActivityRecord a = mHistory.get(i);
+ if (a.info.packageName.equals(packageName)) {
+ a.forceNewConfig = true;
+ if (starting != null && a == starting && a.visible) {
+ a.startFreezingScreenLocked(starting.app, ActivityInfo.CONFIG_SCREEN_LAYOUT);
+ }
+ }
+ }
+
+ return starting;
+ }
}
diff --git a/services/java/com/android/server/am/CompatModePackages.java b/services/java/com/android/server/am/CompatModePackages.java
index 3a6492e..863bdad 100644
--- a/services/java/com/android/server/am/CompatModePackages.java
+++ b/services/java/com/android/server/am/CompatModePackages.java
@@ -295,20 +295,8 @@
Message msg = mHandler.obtainMessage(MSG_WRITE);
mHandler.sendMessageDelayed(msg, 10000);
- ActivityRecord starting = mService.mMainStack.topRunningActivityLocked(null);
-
- // All activities that came from the package must be
- // restarted as if there was a config change.
- for (int i=mService.mMainStack.mHistory.size()-1; i>=0; i--) {
- ActivityRecord a = (ActivityRecord)mService.mMainStack.mHistory.get(i);
- if (a.info.packageName.equals(packageName)) {
- a.forceNewConfig = true;
- if (starting != null && a == starting && a.visible) {
- a.startFreezingScreenLocked(starting.app,
- ActivityInfo.CONFIG_SCREEN_LAYOUT);
- }
- }
- }
+
+ ActivityRecord starting = mService.mMainStack.restartPackage(packageName);
// Tell all processes that loaded this package about the change.
for (int i=mService.mLruProcesses.size()-1; i>=0; i--) {
diff --git a/services/java/com/android/server/am/PendingThumbnailsRecord.java b/services/java/com/android/server/am/PendingThumbnailsRecord.java
index ed478c9..c460791 100644
--- a/services/java/com/android/server/am/PendingThumbnailsRecord.java
+++ b/services/java/com/android/server/am/PendingThumbnailsRecord.java
@@ -27,13 +27,13 @@
class PendingThumbnailsRecord
{
final IThumbnailReceiver receiver; // who is waiting.
- HashSet pendingRecords; // HistoryRecord objects we still wait for.
+ final HashSet<ActivityRecord> pendingRecords; // HistoryRecord objects we still wait for.
boolean finished; // Is pendingRecords empty?
PendingThumbnailsRecord(IThumbnailReceiver _receiver)
{
receiver = _receiver;
- pendingRecords = new HashSet();
+ pendingRecords = new HashSet<ActivityRecord>();
finished = false;
}
}
diff --git a/services/java/com/android/server/pm/PackageManagerService.java b/services/java/com/android/server/pm/PackageManagerService.java
index 46d2cca..5f44ff4 100644
--- a/services/java/com/android/server/pm/PackageManagerService.java
+++ b/services/java/com/android/server/pm/PackageManagerService.java
@@ -110,6 +110,7 @@
import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
+import android.os.UserManager;
import android.os.Environment.UserEnvironment;
import android.security.SystemKeyStore;
import android.util.DisplayMetrics;
@@ -185,6 +186,7 @@
private static final int LOG_UID = Process.LOG_UID;
private static final int NFC_UID = Process.NFC_UID;
private static final int BLUETOOTH_UID = Process.BLUETOOTH_UID;
+ private static final int SHELL_UID = Process.SHELL_UID;
private static final boolean GET_CERTIFICATES = true;
@@ -974,6 +976,7 @@
mSettings.addSharedUserLPw("android.uid.log", LOG_UID, ApplicationInfo.FLAG_SYSTEM);
mSettings.addSharedUserLPw("android.uid.nfc", NFC_UID, ApplicationInfo.FLAG_SYSTEM);
mSettings.addSharedUserLPw("android.uid.bluetooth", BLUETOOTH_UID, ApplicationInfo.FLAG_SYSTEM);
+ mSettings.addSharedUserLPw("android.uid.shell", SHELL_UID, ApplicationInfo.FLAG_SYSTEM);
String separateProcesses = SystemProperties.get("debug.separate_processes");
if (separateProcesses != null && separateProcesses.length() > 0) {
@@ -5649,6 +5652,14 @@
null);
final int uid = Binder.getCallingUid();
+ if (!isUserAllowed(uid, UserManager.ALLOW_INSTALL_APPS)) {
+ try {
+ observer.packageInstalled("", PackageManager.INSTALL_FAILED_USER_RESTRICTED);
+ } catch (RemoteException re) {
+ }
+ return;
+ }
+
UserHandle user;
if ((flags&PackageManager.INSTALL_ALL_USERS) != 0) {
user = UserHandle.ALL;
@@ -5685,6 +5696,9 @@
PackageSetting pkgSetting;
final int uid = Binder.getCallingUid();
final int userId = UserHandle.getUserId(uid);
+ if (!isUserAllowed(uid, UserManager.ALLOW_INSTALL_APPS)) {
+ return PackageManager.INSTALL_FAILED_USER_RESTRICTED;
+ }
long callingId = Binder.clearCallingIdentity();
try {
@@ -5715,7 +5729,19 @@
return PackageManager.INSTALL_SUCCEEDED;
}
-
+
+ private boolean isUserAllowed(int callingUid, String restrictionKey) {
+ if (callingUid != android.os.Process.myUid()) {
+ Bundle restrictions = sUserManager.getUserRestrictions(
+ UserHandle.getUserId(callingUid));
+ if (!restrictions.getBoolean(UserManager.ALLOW_INSTALL_APPS)) {
+ Log.w(TAG, "User does not have permission to: " + restrictionKey);
+ return false;
+ }
+ }
+ return true;
+ }
+
@Override
public void verifyPendingInstall(int id, int verificationCode) throws RemoteException {
mContext.enforceCallingOrSelfPermission(
@@ -8071,6 +8097,14 @@
android.Manifest.permission.DELETE_PACKAGES, null);
// Queue up an async operation since the package deletion may take a little while.
final int uid = Binder.getCallingUid();
+ if (!isUserAllowed(uid, UserManager.ALLOW_UNINSTALL_APPS)) {
+ try {
+ observer.packageDeleted(packageName, PackageManager.DELETE_FAILED_USER_RESTRICTED);
+ } catch (RemoteException re) {
+ }
+ return;
+ }
+
mHandler.post(new Runnable() {
public void run() {
mHandler.removeCallbacks(this);
diff --git a/services/java/com/android/server/pm/UserManagerService.java b/services/java/com/android/server/pm/UserManagerService.java
index dbfe34d..5760dcd 100644
--- a/services/java/com/android/server/pm/UserManagerService.java
+++ b/services/java/com/android/server/pm/UserManagerService.java
@@ -30,6 +30,7 @@
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Binder;
+import android.os.Bundle;
import android.os.Environment;
import android.os.FileUtils;
import android.os.Handler;
@@ -81,6 +82,7 @@
private static final String ATTR_USER_VERSION = "version";
private static final String TAG_USERS = "users";
private static final String TAG_USER = "user";
+ private static final String TAG_RESTRICTIONS = "restrictions";
private static final String USER_INFO_DIR = "system" + File.separator + "users";
private static final String USER_LIST_FILENAME = "userlist.xml";
@@ -104,6 +106,7 @@
private final File mBaseUserPath;
private final SparseArray<UserInfo> mUsers = new SparseArray<UserInfo>();
+ private final SparseArray<Bundle> mUserRestrictions = new SparseArray<Bundle>();
/**
* Set of user IDs being actively removed. Removed IDs linger in this set
@@ -343,6 +346,26 @@
}
}
+ @Override
+ public Bundle getUserRestrictions(int userId) {
+ // checkManageUsersPermission("getUserRestrictions");
+
+ synchronized (mPackagesLock) {
+ Bundle restrictions = mUserRestrictions.get(userId);
+ return restrictions != null ? restrictions : Bundle.EMPTY;
+ }
+ }
+
+ @Override
+ public void setUserRestrictions(Bundle restrictions, int userId) {
+ checkManageUsersPermission("setUserRestrictions");
+
+ synchronized (mPackagesLock) {
+ mUserRestrictions.get(userId).putAll(restrictions);
+ writeUserLocked(mUsers.get(userId));
+ }
+ }
+
/**
* Check if we've hit the limit of how many users can be created.
*/
@@ -454,7 +477,7 @@
while ((type = parser.next()) != XmlPullParser.END_DOCUMENT) {
if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_USER)) {
String id = parser.getAttributeValue(null, ATTR_ID);
- UserInfo user = readUser(Integer.parseInt(id));
+ UserInfo user = readUserLocked(Integer.parseInt(id));
if (user != null) {
mUsers.put(user.id, user);
@@ -568,6 +591,15 @@
serializer.text(userInfo.name);
serializer.endTag(null, TAG_NAME);
+ Bundle restrictions = mUserRestrictions.get(userInfo.id);
+ if (restrictions != null) {
+ serializer.startTag(null, TAG_RESTRICTIONS);
+ writeBoolean(serializer, restrictions, UserManager.ALLOW_CONFIG_WIFI);
+ writeBoolean(serializer, restrictions, UserManager.ALLOW_MODIFY_ACCOUNTS);
+ writeBoolean(serializer, restrictions, UserManager.ALLOW_INSTALL_APPS);
+ writeBoolean(serializer, restrictions, UserManager.ALLOW_UNINSTALL_APPS);
+ serializer.endTag(null, TAG_RESTRICTIONS);
+ }
serializer.endTag(null, TAG_USER);
serializer.endDocument();
@@ -620,7 +652,7 @@
}
}
- private UserInfo readUser(int id) {
+ private UserInfo readUserLocked(int id) {
int flags = 0;
int serialNumber = id;
String name = null;
@@ -628,6 +660,8 @@
long creationTime = 0L;
long lastLoggedInTime = 0L;
boolean partial = false;
+ Bundle restrictions = new Bundle();
+ initRestrictionsToDefaults(restrictions);
FileInputStream fis = null;
try {
@@ -663,13 +697,23 @@
partial = true;
}
- while ((type = parser.next()) != XmlPullParser.START_TAG
- && type != XmlPullParser.END_DOCUMENT) {
- }
- if (type == XmlPullParser.START_TAG && parser.getName().equals(TAG_NAME)) {
- type = parser.next();
- if (type == XmlPullParser.TEXT) {
- name = parser.getText();
+ int outerDepth = parser.getDepth();
+ while ((type = parser.next()) != XmlPullParser.END_DOCUMENT
+ && (type != XmlPullParser.END_TAG || parser.getDepth() > outerDepth)) {
+ if (type == XmlPullParser.END_TAG || type == XmlPullParser.TEXT) {
+ continue;
+ }
+ String tag = parser.getName();
+ if (TAG_NAME.equals(tag)) {
+ type = parser.next();
+ if (type == XmlPullParser.TEXT) {
+ name = parser.getText();
+ }
+ } else if (TAG_RESTRICTIONS.equals(tag)) {
+ readBoolean(parser, restrictions, UserManager.ALLOW_CONFIG_WIFI);
+ readBoolean(parser, restrictions, UserManager.ALLOW_MODIFY_ACCOUNTS);
+ readBoolean(parser, restrictions, UserManager.ALLOW_INSTALL_APPS);
+ readBoolean(parser, restrictions, UserManager.ALLOW_UNINSTALL_APPS);
}
}
}
@@ -679,6 +723,7 @@
userInfo.creationTime = creationTime;
userInfo.lastLoggedInTime = lastLoggedInTime;
userInfo.partial = partial;
+ mUserRestrictions.append(id, restrictions);
return userInfo;
} catch (IOException ioe) {
@@ -694,6 +739,27 @@
return null;
}
+ private void readBoolean(XmlPullParser parser, Bundle restrictions,
+ String restrictionKey) {
+ String value = parser.getAttributeValue(null, restrictionKey);
+ restrictions.putBoolean(restrictionKey, value == null ? true : Boolean.parseBoolean(value));
+ }
+
+ private void writeBoolean(XmlSerializer xml, Bundle restrictions, String restrictionKey)
+ throws IOException {
+ if (restrictions.containsKey(restrictionKey)) {
+ xml.attribute(null, restrictionKey,
+ Boolean.toString(restrictions.getBoolean(restrictionKey)));
+ }
+ }
+
+ private void initRestrictionsToDefaults(Bundle restrictions) {
+ restrictions.putBoolean(UserManager.ALLOW_CONFIG_WIFI, true);
+ restrictions.putBoolean(UserManager.ALLOW_MODIFY_ACCOUNTS, true);
+ restrictions.putBoolean(UserManager.ALLOW_INSTALL_APPS, true);
+ restrictions.putBoolean(UserManager.ALLOW_UNINSTALL_APPS, true);
+ }
+
private int readIntAttribute(XmlPullParser parser, String attr, int defaultValue) {
String valueString = parser.getAttributeValue(null, attr);
if (valueString == null) return defaultValue;
diff --git a/services/java/com/android/server/wm/DisplayMagnifier.java b/services/java/com/android/server/wm/DisplayMagnifier.java
index 6e876f6..61093ad 100644
--- a/services/java/com/android/server/wm/DisplayMagnifier.java
+++ b/services/java/com/android/server/wm/DisplayMagnifier.java
@@ -86,8 +86,8 @@
mContext = windowManagerService.mContext;
mWindowManagerService = windowManagerService;
mCallbacks = callbacks;
- mMagnifedViewport = new MagnifiedViewport();
mHandler = new MyHandler(mWindowManagerService.mH.getLooper());
+ mMagnifedViewport = new MagnifiedViewport();
mLongAnimationDuration = mContext.getResources().getInteger(
com.android.internal.R.integer.config_longAnimTime);
}
@@ -273,6 +273,7 @@
mContext.getResources().getDisplayMetrics());
mHalfBorderWidth = (int) (mBorderWidth + 0.5) / 2;
mWindow = new ViewportWindow(mContext);
+ recomputeBoundsLocked();
}
public void updateMagnificationSpecLocked(MagnificationSpec spec) {
diff --git a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
index 1758d93..c4911a0 100644
--- a/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/UserManagerTest.java
@@ -21,8 +21,10 @@
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.UserInfo;
+import android.os.Bundle;
import android.os.Debug;
import android.os.Environment;
+import android.os.UserHandle;
import android.os.UserManager;
import android.test.AndroidTestCase;
@@ -140,6 +142,20 @@
}
}
+ public void testRestrictions() {
+ List<UserInfo> users = mUserManager.getUsers();
+ if (users.size() > 1) {
+ Bundle restrictions = new Bundle();
+ restrictions.putBoolean(UserManager.ALLOW_INSTALL_APPS, false);
+ restrictions.putBoolean(UserManager.ALLOW_CONFIG_WIFI, true);
+ mUserManager.setUserRestrictions(restrictions, new UserHandle(users.get(1).id));
+ Bundle stored = mUserManager.getUserRestrictions(new UserHandle(users.get(1).id));
+ assertEquals(stored.getBoolean(UserManager.ALLOW_CONFIG_WIFI), true);
+ assertEquals(stored.getBoolean(UserManager.ALLOW_UNINSTALL_APPS), true);
+ assertEquals(stored.getBoolean(UserManager.ALLOW_INSTALL_APPS), false);
+ }
+ }
+
private void removeUser(int userId) {
synchronized (mUserLock) {
mUserManager.removeUser(userId);
@@ -151,4 +167,5 @@
}
}
}
+
}