Multi-user - wallpaper service
- Allow each user to have their own wallpaper (live or static). - Migrate old wallpaper on upgrade. - Update SystemBackupAgent to backup/restore from primary user's new wallpaper directory. Reduce dependency on Binder.getOrigCallingUser() by passing the userId for bindService. Change-Id: I19c8c3296d3d2efa7f28f951d4b84407489e2166
This commit is contained in:
@ -670,8 +670,9 @@ public abstract class ActivityManagerNative extends Binder implements IActivityM
|
||||
String resolvedType = data.readString();
|
||||
b = data.readStrongBinder();
|
||||
int fl = data.readInt();
|
||||
int userId = data.readInt();
|
||||
IServiceConnection conn = IServiceConnection.Stub.asInterface(b);
|
||||
int res = bindService(app, token, service, resolvedType, conn, fl);
|
||||
int res = bindService(app, token, service, resolvedType, conn, fl, userId);
|
||||
reply.writeNoException();
|
||||
reply.writeInt(res);
|
||||
return true;
|
||||
@ -2288,7 +2289,7 @@ class ActivityManagerProxy implements IActivityManager
|
||||
}
|
||||
public int bindService(IApplicationThread caller, IBinder token,
|
||||
Intent service, String resolvedType, IServiceConnection connection,
|
||||
int flags) throws RemoteException {
|
||||
int flags, int userId) throws RemoteException {
|
||||
Parcel data = Parcel.obtain();
|
||||
Parcel reply = Parcel.obtain();
|
||||
data.writeInterfaceToken(IActivityManager.descriptor);
|
||||
@ -2298,6 +2299,7 @@ class ActivityManagerProxy implements IActivityManager
|
||||
data.writeString(resolvedType);
|
||||
data.writeStrongBinder(connection.asBinder());
|
||||
data.writeInt(flags);
|
||||
data.writeInt(userId);
|
||||
mRemote.transact(BIND_SERVICE_TRANSACTION, data, reply, 0);
|
||||
reply.readException();
|
||||
int res = reply.readInt();
|
||||
|
@ -1125,6 +1125,12 @@ class ContextImpl extends Context {
|
||||
@Override
|
||||
public boolean bindService(Intent service, ServiceConnection conn,
|
||||
int flags) {
|
||||
return bindService(service, conn, flags, UserId.getUserId(Process.myUid()));
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
public boolean bindService(Intent service, ServiceConnection conn, int flags, int userId) {
|
||||
IServiceConnection sd;
|
||||
if (mPackageInfo != null) {
|
||||
sd = mPackageInfo.getServiceDispatcher(conn, getOuterContext(),
|
||||
@ -1143,7 +1149,7 @@ class ContextImpl extends Context {
|
||||
int res = ActivityManagerNative.getDefault().bindService(
|
||||
mMainThread.getApplicationThread(), getActivityToken(),
|
||||
service, service.resolveTypeIfNeeded(getContentResolver()),
|
||||
sd, flags);
|
||||
sd, flags, userId);
|
||||
if (res < 0) {
|
||||
throw new SecurityException(
|
||||
"Not allowed to bind to service " + service);
|
||||
|
@ -166,7 +166,7 @@ public interface IActivityManager extends IInterface {
|
||||
int id, Notification notification, boolean keepNotification) throws RemoteException;
|
||||
public int bindService(IApplicationThread caller, IBinder token,
|
||||
Intent service, String resolvedType,
|
||||
IServiceConnection connection, int flags) throws RemoteException;
|
||||
IServiceConnection connection, int flags, int userId) throws RemoteException;
|
||||
public boolean unbindService(IServiceConnection connection) throws RemoteException;
|
||||
public void publishService(IBinder token,
|
||||
Intent intent, IBinder service) throws RemoteException;
|
||||
|
@ -30,6 +30,7 @@ import android.graphics.PorterDuffXfermode;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.BitmapDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Binder;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
|
@ -38,15 +38,23 @@ public class WallpaperBackupHelper extends FileBackupHelperBase implements Backu
|
||||
private static final boolean DEBUG = false;
|
||||
|
||||
// This path must match what the WallpaperManagerService uses
|
||||
private static final String WALLPAPER_IMAGE = "/data/data/com.android.settings/files/wallpaper";
|
||||
// TODO: Will need to change if backing up non-primary user's wallpaper
|
||||
public static final String WALLPAPER_IMAGE = "/data/system/users/0/wallpaper";
|
||||
public static final String WALLPAPER_INFO = "/data/system/users/0/wallpaper_info.xml";
|
||||
// Use old keys to keep legacy data compatibility and avoid writing two wallpapers
|
||||
public static final String WALLPAPER_IMAGE_KEY =
|
||||
"/data/data/com.android.settings/files/wallpaper";
|
||||
public static final String WALLPAPER_INFO_KEY = "/data/system/wallpaper_info.xml";
|
||||
|
||||
// Stage file - should be adjacent to the WALLPAPER_IMAGE location. The wallpapers
|
||||
// will be saved to this file from the restore stream, then renamed to the proper
|
||||
// location if it's deemed suitable.
|
||||
private static final String STAGE_FILE = "/data/data/com.android.settings/files/wallpaper-tmp";
|
||||
// TODO: Will need to change if backing up non-primary user's wallpaper
|
||||
private static final String STAGE_FILE = "/data/system/users/0/wallpaper-tmp";
|
||||
|
||||
Context mContext;
|
||||
String[] mFiles;
|
||||
String[] mKeys;
|
||||
double mDesiredMinWidth;
|
||||
double mDesiredMinHeight;
|
||||
|
||||
@ -57,11 +65,12 @@ public class WallpaperBackupHelper extends FileBackupHelperBase implements Backu
|
||||
* @param context
|
||||
* @param files
|
||||
*/
|
||||
public WallpaperBackupHelper(Context context, String... files) {
|
||||
public WallpaperBackupHelper(Context context, String[] files, String[] keys) {
|
||||
super(context);
|
||||
|
||||
mContext = context;
|
||||
mFiles = files;
|
||||
mKeys = keys;
|
||||
|
||||
WallpaperManager wpm;
|
||||
wpm = (WallpaperManager) context.getSystemService(Context.WALLPAPER_SERVICE);
|
||||
@ -89,7 +98,7 @@ public class WallpaperBackupHelper extends FileBackupHelperBase implements Backu
|
||||
*/
|
||||
public void performBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
|
||||
ParcelFileDescriptor newState) {
|
||||
performBackup_checked(oldState, data, newState, mFiles, mFiles);
|
||||
performBackup_checked(oldState, data, newState, mFiles, mKeys);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -99,8 +108,8 @@ public class WallpaperBackupHelper extends FileBackupHelperBase implements Backu
|
||||
*/
|
||||
public void restoreEntity(BackupDataInputStream data) {
|
||||
final String key = data.getKey();
|
||||
if (isKeyInList(key, mFiles)) {
|
||||
if (key.equals(WALLPAPER_IMAGE)) {
|
||||
if (isKeyInList(key, mKeys)) {
|
||||
if (key.equals(WALLPAPER_IMAGE_KEY)) {
|
||||
// restore the file to the stage for inspection
|
||||
File f = new File(STAGE_FILE);
|
||||
if (writeFile(f, data)) {
|
||||
@ -135,9 +144,9 @@ public class WallpaperBackupHelper extends FileBackupHelperBase implements Backu
|
||||
f.delete();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// Some other normal file; just decode it to its destination
|
||||
File f = new File(key);
|
||||
} else if (key.equals(WALLPAPER_INFO_KEY)) {
|
||||
// XML file containing wallpaper info
|
||||
File f = new File(WALLPAPER_INFO);
|
||||
writeFile(f, data);
|
||||
}
|
||||
}
|
||||
|
@ -1306,6 +1306,15 @@ public abstract class Context {
|
||||
public abstract boolean bindService(Intent service, ServiceConnection conn,
|
||||
int flags);
|
||||
|
||||
/**
|
||||
* Same as {@link #bindService(Intent, ServiceConnection, int)}, but with an explicit userId
|
||||
* argument for use by system server and other multi-user aware code.
|
||||
* @hide
|
||||
*/
|
||||
public boolean bindService(Intent service, ServiceConnection conn, int flags, int userId) {
|
||||
throw new RuntimeException("Not implemented. Must override in a subclass.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Disconnect from an application service. You will no longer receive
|
||||
* calls as the service is restarted, and the service is now allowed to
|
||||
|
@ -370,6 +370,12 @@ public class ContextWrapper extends Context {
|
||||
return mBase.bindService(service, conn, flags);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
public boolean bindService(Intent service, ServiceConnection conn, int flags, int userId) {
|
||||
return mBase.bindService(service, conn, flags, userId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unbindService(ServiceConnection conn) {
|
||||
mBase.unbindService(conn);
|
||||
|
@ -3380,7 +3380,8 @@ public class PackageParser {
|
||||
|
||||
public static final ServiceInfo generateServiceInfo(Service s, int flags, int userId) {
|
||||
if (s == null) return null;
|
||||
if (!copyNeeded(flags, s.owner, s.metaData) && userId == 0) {
|
||||
if (!copyNeeded(flags, s.owner, s.metaData)
|
||||
&& userId == UserId.getUserId(s.info.applicationInfo.uid)) {
|
||||
return s.info;
|
||||
}
|
||||
// Make shallow copies so we can store the metadata safely
|
||||
|
@ -73,6 +73,10 @@ public final class UserId {
|
||||
}
|
||||
}
|
||||
|
||||
public static final int getCallingUserId() {
|
||||
return getUserId(Binder.getCallingUid());
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the uid that is composed from the userId and the appId.
|
||||
* @hide
|
||||
|
@ -52,7 +52,6 @@ writeEntityHeader_native(JNIEnv* env, jobject clazz, int w, jstring key, int dat
|
||||
if (keyUTF == NULL) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
err = writer->WriteEntityHeader(String8(keyUTF), dataSize);
|
||||
|
||||
env->ReleaseStringUTFChars(key, keyUTF);
|
||||
|
@ -573,12 +573,13 @@ class AppWidgetServiceImpl {
|
||||
mBoundRemoteViewsServices.remove(key);
|
||||
}
|
||||
|
||||
int userId = UserId.getUserId(id.provider.uid);
|
||||
// Bind to the RemoteViewsService (which will trigger a callback to the
|
||||
// RemoteViewsAdapter.onServiceConnected())
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
conn = new ServiceConnectionProxy(key, connection);
|
||||
mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE);
|
||||
mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE, userId);
|
||||
mBoundRemoteViewsServices.put(key, conn);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
@ -638,11 +639,11 @@ class AppWidgetServiceImpl {
|
||||
|
||||
// Check if we need to destroy any services (if no other app widgets are
|
||||
// referencing the same service)
|
||||
decrementAppWidgetServiceRefCount(appWidgetId);
|
||||
decrementAppWidgetServiceRefCount(id);
|
||||
}
|
||||
|
||||
// Destroys the cached factory on the RemoteViewsService's side related to the specified intent
|
||||
private void destroyRemoteViewsService(final Intent intent) {
|
||||
private void destroyRemoteViewsService(final Intent intent, AppWidgetId id) {
|
||||
final ServiceConnection conn = new ServiceConnection() {
|
||||
@Override
|
||||
public void onServiceConnected(ComponentName name, IBinder service) {
|
||||
@ -663,11 +664,12 @@ class AppWidgetServiceImpl {
|
||||
}
|
||||
};
|
||||
|
||||
int userId = UserId.getUserId(id.provider.uid);
|
||||
// Bind to the service and remove the static intent->factory mapping in the
|
||||
// RemoteViewsService.
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE);
|
||||
mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE, userId);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
@ -687,16 +689,16 @@ class AppWidgetServiceImpl {
|
||||
|
||||
// Subtracts from the ref-count for a given RemoteViewsService intent, prompting a delete if
|
||||
// the ref-count reaches zero.
|
||||
private void decrementAppWidgetServiceRefCount(int appWidgetId) {
|
||||
private void decrementAppWidgetServiceRefCount(AppWidgetId id) {
|
||||
Iterator<FilterComparison> it = mRemoteViewsServicesAppWidgets.keySet().iterator();
|
||||
while (it.hasNext()) {
|
||||
final FilterComparison key = it.next();
|
||||
final HashSet<Integer> ids = mRemoteViewsServicesAppWidgets.get(key);
|
||||
if (ids.remove(appWidgetId)) {
|
||||
if (ids.remove(id.appWidgetId)) {
|
||||
// If we have removed the last app widget referencing this service, then we
|
||||
// should destroy it and remove it from this set
|
||||
if (ids.isEmpty()) {
|
||||
destroyRemoteViewsService(key.getIntent());
|
||||
destroyRemoteViewsService(key.getIntent(), id);
|
||||
it.remove();
|
||||
}
|
||||
}
|
||||
@ -888,10 +890,11 @@ class AppWidgetServiceImpl {
|
||||
}
|
||||
};
|
||||
|
||||
int userId = UserId.getUserId(id.provider.uid);
|
||||
// Bind to the service and call onDataSetChanged()
|
||||
final long token = Binder.clearCallingIdentity();
|
||||
try {
|
||||
mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE);
|
||||
mContext.bindService(intent, conn, Context.BIND_AUTO_CREATE, userId);
|
||||
} finally {
|
||||
Binder.restoreCallingIdentity(token);
|
||||
}
|
||||
@ -1343,7 +1346,6 @@ class AppWidgetServiceImpl {
|
||||
|
||||
void readStateFromFileLocked(FileInputStream stream) {
|
||||
boolean success = false;
|
||||
|
||||
try {
|
||||
XmlPullParser parser = Xml.newPullParser();
|
||||
parser.setInput(stream, null);
|
||||
@ -1475,7 +1477,7 @@ class AppWidgetServiceImpl {
|
||||
}
|
||||
|
||||
AtomicFile savedStateFile() {
|
||||
int userId = Binder.getOrigCallingUser();
|
||||
int userId = UserId.getCallingUserId();
|
||||
File dir = new File("/data/system/users/" + userId);
|
||||
File settingsFile = new File(dir, SETTINGS_FILENAME);
|
||||
if (!dir.exists()) {
|
||||
|
@ -44,12 +44,16 @@ public class SystemBackupAgent extends BackupAgentHelper {
|
||||
private static final String WALLPAPER_IMAGE_FILENAME = "wallpaper";
|
||||
private static final String WALLPAPER_INFO_FILENAME = "wallpaper_info.xml";
|
||||
|
||||
private static final String WALLPAPER_IMAGE_DIR = "/data/data/com.android.settings/files";
|
||||
private static final String WALLPAPER_IMAGE = WALLPAPER_IMAGE_DIR + "/" + WALLPAPER_IMAGE_FILENAME;
|
||||
|
||||
private static final String WALLPAPER_INFO_DIR = "/data/system";
|
||||
private static final String WALLPAPER_INFO = WALLPAPER_INFO_DIR + "/" + WALLPAPER_INFO_FILENAME;
|
||||
// TODO: Will need to change if backing up non-primary user's wallpaper
|
||||
private static final String WALLPAPER_IMAGE_DIR = "/data/system/users/0";
|
||||
private static final String WALLPAPER_IMAGE = WallpaperBackupHelper.WALLPAPER_IMAGE;
|
||||
|
||||
// TODO: Will need to change if backing up non-primary user's wallpaper
|
||||
private static final String WALLPAPER_INFO_DIR = "/data/system/users/0";
|
||||
private static final String WALLPAPER_INFO = WallpaperBackupHelper.WALLPAPER_INFO;
|
||||
// Use old keys to keep legacy data compatibility and avoid writing two wallpapers
|
||||
private static final String WALLPAPER_IMAGE_KEY = WallpaperBackupHelper.WALLPAPER_IMAGE_KEY;
|
||||
private static final String WALLPAPER_INFO_KEY = WallpaperBackupHelper.WALLPAPER_INFO_KEY;
|
||||
|
||||
@Override
|
||||
public void onBackup(ParcelFileDescriptor oldState, BackupDataOutput data,
|
||||
@ -58,13 +62,15 @@ public class SystemBackupAgent extends BackupAgentHelper {
|
||||
WallpaperManagerService wallpaper = (WallpaperManagerService)ServiceManager.getService(
|
||||
Context.WALLPAPER_SERVICE);
|
||||
String[] files = new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO };
|
||||
if (wallpaper != null && wallpaper.mName != null && wallpaper.mName.length() > 0) {
|
||||
String[] keys = new String[] { WALLPAPER_IMAGE_KEY, WALLPAPER_INFO_KEY };
|
||||
if (wallpaper != null && wallpaper.getName() != null && wallpaper.getName().length() > 0) {
|
||||
// When the wallpaper has a name, back up the info by itself.
|
||||
// TODO: Don't rely on the innards of the service object like this!
|
||||
// TODO: Send a delete for any stored wallpaper image in this case?
|
||||
files = new String[] { WALLPAPER_INFO };
|
||||
keys = new String[] { WALLPAPER_INFO_KEY };
|
||||
}
|
||||
addHelper("wallpaper", new WallpaperBackupHelper(SystemBackupAgent.this, files));
|
||||
addHelper("wallpaper", new WallpaperBackupHelper(SystemBackupAgent.this, files, keys));
|
||||
super.onBackup(oldState, data, newState);
|
||||
}
|
||||
|
||||
@ -90,9 +96,11 @@ public class SystemBackupAgent extends BackupAgentHelper {
|
||||
throws IOException {
|
||||
// On restore, we also support a previous data schema "system_files"
|
||||
addHelper("wallpaper", new WallpaperBackupHelper(SystemBackupAgent.this,
|
||||
new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO }));
|
||||
new String[] { WALLPAPER_IMAGE, WALLPAPER_INFO },
|
||||
new String[] { WALLPAPER_IMAGE_KEY, WALLPAPER_INFO_KEY} ));
|
||||
addHelper("system_files", new WallpaperBackupHelper(SystemBackupAgent.this,
|
||||
new String[] { WALLPAPER_IMAGE }));
|
||||
new String[] { WALLPAPER_IMAGE },
|
||||
new String[] { WALLPAPER_IMAGE_KEY} ));
|
||||
|
||||
try {
|
||||
super.onRestore(data, appVersionCode, newState);
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -49,6 +49,7 @@ import android.app.Notification;
|
||||
import android.app.NotificationManager;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.Service;
|
||||
import android.app.WallpaperManager;
|
||||
import android.app.backup.IBackupManager;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.BroadcastReceiver;
|
||||
@ -1363,24 +1364,6 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
*/
|
||||
final ArrayList mCancelledThumbnails = new ArrayList();
|
||||
|
||||
/**
|
||||
* All of the currently running global content providers. Keys are a
|
||||
* string containing the provider name and values are a
|
||||
* ContentProviderRecord object containing the data about it. Note
|
||||
* that a single provider may be published under multiple names, so
|
||||
* there may be multiple entries here for a single one in mProvidersByClass.
|
||||
*/
|
||||
final HashMap<String, ContentProviderRecord> mProvidersByName
|
||||
= new HashMap<String, ContentProviderRecord>();
|
||||
|
||||
/**
|
||||
* All of the currently running global content providers. Keys are a
|
||||
* string containing the provider's implementation class and values are a
|
||||
* ContentProviderRecord object containing the data about it.
|
||||
*/
|
||||
final HashMap<ComponentName, ContentProviderRecord> mProvidersByClass
|
||||
= new HashMap<ComponentName, ContentProviderRecord>();
|
||||
|
||||
final ProviderMap mProviderMap = new ProviderMap();
|
||||
|
||||
/**
|
||||
@ -4434,7 +4417,7 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
}
|
||||
|
||||
ArrayList<ContentProviderRecord> providers = new ArrayList<ContentProviderRecord>();
|
||||
for (ContentProviderRecord provider : mProvidersByClass.values()) {
|
||||
for (ContentProviderRecord provider : mProviderMap.getProvidersByClass(-1).values()) {
|
||||
if (provider.info.packageName.equals(name)
|
||||
&& (provider.proc == null || evenPersistent || !provider.proc.persistent)) {
|
||||
if (!doit) {
|
||||
@ -11361,18 +11344,18 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
}
|
||||
|
||||
private ServiceLookupResult retrieveServiceLocked(Intent service,
|
||||
String resolvedType, int callingPid, int callingUid) {
|
||||
String resolvedType, int callingPid, int callingUid, int userId) {
|
||||
ServiceRecord r = null;
|
||||
if (DEBUG_SERVICE)
|
||||
Slog.v(TAG, "retrieveServiceLocked: " + service + " type=" + resolvedType
|
||||
+ " origCallingUid=" + callingUid);
|
||||
+ " callingUid=" + callingUid);
|
||||
|
||||
if (service.getComponent() != null) {
|
||||
r = mServiceMap.getServiceByName(service.getComponent(), Binder.getOrigCallingUser());
|
||||
r = mServiceMap.getServiceByName(service.getComponent(), userId);
|
||||
}
|
||||
if (r == null) {
|
||||
Intent.FilterComparison filter = new Intent.FilterComparison(service);
|
||||
r = mServiceMap.getServiceByIntent(filter, Binder.getOrigCallingUser());
|
||||
r = mServiceMap.getServiceByIntent(filter, userId);
|
||||
}
|
||||
if (r == null) {
|
||||
try {
|
||||
@ -11386,13 +11369,12 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
": not found");
|
||||
return null;
|
||||
}
|
||||
if (Binder.getOrigCallingUser() > 0) {
|
||||
sInfo.applicationInfo = getAppInfoForUser(sInfo.applicationInfo,
|
||||
Binder.getOrigCallingUser());
|
||||
if (userId > 0) {
|
||||
sInfo.applicationInfo = getAppInfoForUser(sInfo.applicationInfo, userId);
|
||||
}
|
||||
ComponentName name = new ComponentName(
|
||||
sInfo.applicationInfo.packageName, sInfo.name);
|
||||
r = mServiceMap.getServiceByName(name, Binder.getOrigCallingUser());
|
||||
r = mServiceMap.getServiceByName(name, userId);
|
||||
if (r == null) {
|
||||
Intent.FilterComparison filter = new Intent.FilterComparison(
|
||||
service.cloneFilter());
|
||||
@ -11956,7 +11938,7 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
|
||||
ServiceLookupResult res =
|
||||
retrieveServiceLocked(service, resolvedType,
|
||||
callingPid, callingUid);
|
||||
callingPid, callingUid, UserId.getUserId(callingUid));
|
||||
if (res == null) {
|
||||
return null;
|
||||
}
|
||||
@ -12206,13 +12188,15 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
|
||||
public int bindService(IApplicationThread caller, IBinder token,
|
||||
Intent service, String resolvedType,
|
||||
IServiceConnection connection, int flags) {
|
||||
IServiceConnection connection, int flags, int userId) {
|
||||
enforceNotIsolatedCaller("bindService");
|
||||
// Refuse possible leaked file descriptors
|
||||
if (service != null && service.hasFileDescriptors() == true) {
|
||||
throw new IllegalArgumentException("File descriptors passed in Intent");
|
||||
}
|
||||
|
||||
checkValidCaller(Binder.getCallingUid(), userId);
|
||||
|
||||
synchronized(this) {
|
||||
if (DEBUG_SERVICE) Slog.v(TAG, "bindService: " + service
|
||||
+ " type=" + resolvedType + " conn=" + connection.asBinder()
|
||||
@ -12262,7 +12246,7 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
|
||||
ServiceLookupResult res =
|
||||
retrieveServiceLocked(service, resolvedType,
|
||||
Binder.getCallingPid(), Binder.getOrigCallingUid());
|
||||
Binder.getCallingPid(), Binder.getCallingUid(), userId);
|
||||
if (res == null) {
|
||||
return 0;
|
||||
}
|
||||
@ -15259,6 +15243,25 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
|
||||
private int mCurrentUserId;
|
||||
private SparseIntArray mLoggedInUsers = new SparseIntArray(5);
|
||||
private ArrayList<UserListener> mUserListeners = new ArrayList<UserListener>(3);
|
||||
|
||||
public interface UserListener {
|
||||
public void onUserChanged(int userId);
|
||||
|
||||
public void onUserAdded(int userId);
|
||||
|
||||
public void onUserRemoved(int userId);
|
||||
|
||||
public void onUserLoggedOut(int userId);
|
||||
}
|
||||
|
||||
public void addUserListener(UserListener listener) {
|
||||
synchronized (this) {
|
||||
if (!mUserListeners.contains(listener)) {
|
||||
mUserListeners.add(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean switchUser(int userId) {
|
||||
final int callingUid = Binder.getCallingUid();
|
||||
@ -15269,6 +15272,8 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
if (mCurrentUserId == userId)
|
||||
return true;
|
||||
|
||||
ArrayList<UserListener> listeners;
|
||||
|
||||
synchronized (this) {
|
||||
// Check if user is already logged in, otherwise check if user exists first before
|
||||
// adding to the list of logged in users.
|
||||
@ -15284,6 +15289,12 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
if (!haveActivities) {
|
||||
startHomeActivityLocked(userId);
|
||||
}
|
||||
|
||||
listeners = (ArrayList<UserListener>) mUserListeners.clone();
|
||||
}
|
||||
// Inform the listeners
|
||||
for (UserListener listener : listeners) {
|
||||
listener.onUserChanged(userId);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@ -15303,6 +15314,12 @@ public final class ActivityManagerService extends ActivityManagerNative
|
||||
return false;
|
||||
}
|
||||
|
||||
private void checkValidCaller(int uid, int userId) {
|
||||
if (UserId.getUserId(uid) == userId || uid == Process.SYSTEM_UID || uid == 0) return;
|
||||
|
||||
throw new SecurityException("Caller uid=" + uid
|
||||
+ " is not privileged to communicate with user=" + userId);
|
||||
}
|
||||
|
||||
private int applyUserId(int uid, int userId) {
|
||||
return UserId.getUid(userId, uid);
|
||||
|
@ -158,7 +158,7 @@ public class ProviderMap {
|
||||
}
|
||||
}
|
||||
|
||||
private HashMap<ComponentName, ContentProviderRecord> getProvidersByClass(int optionalUserId) {
|
||||
HashMap<ComponentName, ContentProviderRecord> getProvidersByClass(int optionalUserId) {
|
||||
final int userId = optionalUserId >= 0
|
||||
? optionalUserId : Binder.getOrigCallingUser();
|
||||
final HashMap<ComponentName, ContentProviderRecord> map = mProvidersByClassPerUser.get(userId);
|
||||
|
@ -333,6 +333,12 @@ public class MockContext extends Context {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
public boolean bindService(Intent service, ServiceConnection conn, int flags, int userId) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unbindService(ServiceConnection conn) {
|
||||
throw new UnsupportedOperationException();
|
||||
|
Reference in New Issue
Block a user