Merge change Ib839afc3 into eclair-mr2

* changes:
  remove the bind helper and bind directly
This commit is contained in:
Android (Google) Code Review
2009-10-15 13:16:31 -04:00
2 changed files with 45 additions and 275 deletions

View File

@ -21,6 +21,8 @@ import android.content.ContentValues;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import android.content.ServiceConnection;
import android.content.ComponentName;
import android.content.pm.PackageManager; import android.content.pm.PackageManager;
import android.content.pm.RegisteredServicesCache; import android.content.pm.RegisteredServicesCache;
import android.content.pm.PackageInfo; import android.content.pm.PackageInfo;
@ -90,11 +92,8 @@ public class AccountManagerService
// Messages that can be sent on mHandler // Messages that can be sent on mHandler
private static final int MESSAGE_TIMED_OUT = 3; private static final int MESSAGE_TIMED_OUT = 3;
private static final int MESSAGE_CONNECTED = 7;
private static final int MESSAGE_DISCONNECTED = 8;
private final AccountAuthenticatorCache mAuthenticatorCache; private final AccountAuthenticatorCache mAuthenticatorCache;
private final AuthenticatorBindHelper mBindHelper;
private final DatabaseHelper mOpenHelper; private final DatabaseHelper mOpenHelper;
private final SimWatcher mSimWatcher; private final SimWatcher mSimWatcher;
@ -220,8 +219,6 @@ public class AccountManagerService
mAuthenticatorCache = new AccountAuthenticatorCache(mContext); mAuthenticatorCache = new AccountAuthenticatorCache(mContext);
mAuthenticatorCache.setListener(this); mAuthenticatorCache.setListener(this);
mBindHelper = new AuthenticatorBindHelper(mContext, mAuthenticatorCache, mMessageHandler,
MESSAGE_CONNECTED, MESSAGE_DISCONNECTED);
if (SystemProperties.getBoolean("ro.config.sim_password_clear", false)) { if (SystemProperties.getBoolean("ro.config.sim_password_clear", false)) {
mSimWatcher = new SimWatcher(mContext); mSimWatcher = new SimWatcher(mContext);
@ -1072,7 +1069,7 @@ public class AccountManagerService
} }
private abstract class Session extends IAccountAuthenticatorResponse.Stub private abstract class Session extends IAccountAuthenticatorResponse.Stub
implements AuthenticatorBindHelper.Callback, IBinder.DeathRecipient { implements IBinder.DeathRecipient, ServiceConnection {
IAccountManagerResponse mResponse; IAccountManagerResponse mResponse;
final String mAccountType; final String mAccountType;
final boolean mExpectActivityLaunch; final boolean mExpectActivityLaunch;
@ -1154,7 +1151,7 @@ public class AccountManagerService
if (Log.isLoggable(TAG, Log.VERBOSE)) { if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "initiating bind to authenticator type " + mAccountType); Log.v(TAG, "initiating bind to authenticator type " + mAccountType);
} }
if (!mBindHelper.bind(mAccountType, this)) { if (!bindToAuthenticator(mAccountType)) {
Log.d(TAG, "bind attempt failed for " + toDebugString()); Log.d(TAG, "bind attempt failed for " + toDebugString());
onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure"); onError(AccountManager.ERROR_CODE_REMOTE_EXCEPTION, "bind failure");
} }
@ -1163,7 +1160,7 @@ public class AccountManagerService
private void unbind() { private void unbind() {
if (mAuthenticator != null) { if (mAuthenticator != null) {
mAuthenticator = null; mAuthenticator = null;
mBindHelper.unbind(this); mContext.unbindService(this);
} }
} }
@ -1176,7 +1173,7 @@ public class AccountManagerService
mMessageHandler.removeMessages(MESSAGE_TIMED_OUT, this); mMessageHandler.removeMessages(MESSAGE_TIMED_OUT, this);
} }
public void onConnected(IBinder service) { public void onServiceConnected(ComponentName name, IBinder service) {
mAuthenticator = IAccountAuthenticator.Stub.asInterface(service); mAuthenticator = IAccountAuthenticator.Stub.asInterface(service);
try { try {
run(); run();
@ -1186,9 +1183,7 @@ public class AccountManagerService
} }
} }
public abstract void run() throws RemoteException; public void onServiceDisconnected(ComponentName name) {
public void onDisconnected() {
mAuthenticator = null; mAuthenticator = null;
IAccountManagerResponse response = getResponseAndClose(); IAccountManagerResponse response = getResponseAndClose();
if (response != null) { if (response != null) {
@ -1197,6 +1192,8 @@ public class AccountManagerService
} }
} }
public abstract void run() throws RemoteException;
public void onTimedOut() { public void onTimedOut() {
IAccountManagerResponse response = getResponseAndClose(); IAccountManagerResponse response = getResponseAndClose();
if (response != null) { if (response != null) {
@ -1266,6 +1263,39 @@ public class AccountManagerService
} }
} }
} }
/**
* find the component name for the authenticator and initiate a bind
* if no authenticator or the bind fails then return false, otherwise return true
*/
private boolean bindToAuthenticator(String authenticatorType) {
AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo =
mAuthenticatorCache.getServiceInfo(
AuthenticatorDescription.newKey(authenticatorType));
if (authenticatorInfo == null) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "there is no authenticator for " + authenticatorType
+ ", bailing out");
}
return false;
}
Intent intent = new Intent();
intent.setAction(AccountManager.ACTION_AUTHENTICATOR_INTENT);
intent.setComponent(authenticatorInfo.componentName);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
}
if (!mContext.bindService(intent, this, Context.BIND_AUTO_CREATE)) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
}
return false;
}
return true;
}
} }
private class MessageHandler extends Handler { private class MessageHandler extends Handler {
@ -1274,9 +1304,6 @@ public class AccountManagerService
} }
public void handleMessage(Message msg) { public void handleMessage(Message msg) {
if (mBindHelper.handleMessage(msg)) {
return;
}
switch (msg.what) { switch (msg.what) {
case MESSAGE_TIMED_OUT: case MESSAGE_TIMED_OUT:
Session session = (Session)msg.obj; Session session = (Session)msg.obj;
@ -1571,16 +1598,17 @@ public class AccountManagerService
private boolean permissionIsGranted(Account account, String authTokenType, int callerUid) { private boolean permissionIsGranted(Account account, String authTokenType, int callerUid) {
final boolean fromAuthenticator = hasAuthenticatorUid(account.type, callerUid); final boolean fromAuthenticator = hasAuthenticatorUid(account.type, callerUid);
final boolean hasExplicitGrants = hasExplicitlyGrantedPermission(account, authTokenType); final boolean hasExplicitGrants = hasExplicitlyGrantedPermission(account, authTokenType);
final boolean inSystemImage = inSystemImage(callerUid);
if (Log.isLoggable(TAG, Log.VERBOSE)) { if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "checkGrantsOrCallingUidAgainstAuthenticator: caller uid " Log.v(TAG, "checkGrantsOrCallingUidAgainstAuthenticator: caller uid "
+ callerUid + ", account " + account + callerUid + ", account " + account
+ ": is authenticator? " + fromAuthenticator + ": is authenticator? " + fromAuthenticator
+ ", has explicit permission? " + hasExplicitGrants); + ", has explicit permission? " + hasExplicitGrants);
} }
return fromAuthenticator || hasExplicitGrants || inSystemImage(callerUid); return fromAuthenticator || hasExplicitGrants || inSystemImage;
} }
private boolean hasAuthenticatorUid(String accountType, int callingUid) { private boolean hasAuthenticatorcontextUid(String accountType, int callingUid) {
for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo : for (RegisteredServicesCache.ServiceInfo<AuthenticatorDescription> serviceInfo :
mAuthenticatorCache.getAllServices()) { mAuthenticatorCache.getAllServices()) {
if (serviceInfo.type.type.equals(accountType)) { if (serviceInfo.type.type.equals(accountType)) {

View File

@ -1,258 +0,0 @@
/*
* Copyright (C) 2009 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package android.accounts;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Handler;
import android.os.IBinder;
import android.os.Message;
import android.util.Log;
import java.util.ArrayList;
import java.util.Map;
import com.google.android.collect.Lists;
import com.google.android.collect.Maps;
/**
* A helper object that simplifies binding to Account Authenticators. It uses the
* {@link AccountAuthenticatorCache} to find the component name of the authenticators,
* allowing the user to bind by account name. It also allows multiple, simultaneous binds
* to the same authenticator, with each bind call guaranteed to return either
* {@link Callback#onConnected} or {@link Callback#onDisconnected} if the bind() call
* itself succeeds, even if the authenticator is already bound internally.
* @hide
*/
public class AuthenticatorBindHelper {
private static final String TAG = "Accounts";
private final Handler mHandler;
private final Context mContext;
private final int mMessageWhatConnected;
private final int mMessageWhatDisconnected;
private final Map<String, MyServiceConnection> mServiceConnections = Maps.newHashMap();
private final Map<String, ArrayList<Callback>> mServiceUsers = Maps.newHashMap();
private final AccountAuthenticatorCache mAuthenticatorCache;
public AuthenticatorBindHelper(Context context,
AccountAuthenticatorCache authenticatorCache, Handler handler,
int messageWhatConnected, int messageWhatDisconnected) {
mContext = context;
mHandler = handler;
mAuthenticatorCache = authenticatorCache;
mMessageWhatConnected = messageWhatConnected;
mMessageWhatDisconnected = messageWhatDisconnected;
}
public interface Callback {
void onConnected(IBinder service);
void onDisconnected();
}
public boolean bind(String authenticatorType, Callback callback) {
// if the authenticator is connecting or connected then return true
synchronized (mServiceConnections) {
if (mServiceConnections.containsKey(authenticatorType)) {
MyServiceConnection connection = mServiceConnections.get(authenticatorType);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "service connection already exists for " + authenticatorType);
}
mServiceUsers.get(authenticatorType).add(callback);
if (connection.mService != null) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "the service is connected, scheduling a connected message for "
+ authenticatorType);
}
connection.scheduleCallbackConnectedMessage(callback);
} else {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "the service is *not* connected, waiting for for "
+ authenticatorType);
}
}
return true;
}
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "there is no service connection for " + authenticatorType);
}
// otherwise find the component name for the authenticator and initiate a bind
// if no authenticator or the bind fails then return false, otherwise return true
AccountAuthenticatorCache.ServiceInfo<AuthenticatorDescription> authenticatorInfo =
mAuthenticatorCache.getServiceInfo(
AuthenticatorDescription.newKey(authenticatorType));
if (authenticatorInfo == null) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "there is no authenticator for " + authenticatorType
+ ", bailing out");
}
return false;
}
MyServiceConnection connection = new MyServiceConnection(authenticatorType);
Intent intent = new Intent();
intent.setAction("android.accounts.AccountAuthenticator");
intent.setComponent(authenticatorInfo.componentName);
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "performing bindService to " + authenticatorInfo.componentName);
}
if (!mContext.bindService(intent, connection, Context.BIND_AUTO_CREATE)) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "bindService to " + authenticatorInfo.componentName + " failed");
}
return false;
}
mServiceConnections.put(authenticatorType, connection);
mServiceUsers.put(authenticatorType, Lists.newArrayList(callback));
return true;
}
}
public void unbind(Callback callbackToUnbind) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "unbinding callback " + callbackToUnbind);
}
synchronized (mServiceConnections) {
for (Map.Entry<String, ArrayList<Callback>> entry : mServiceUsers.entrySet()) {
final String authenticatorType = entry.getKey();
final ArrayList<Callback> serviceUsers = entry.getValue();
for (Callback callback : serviceUsers) {
if (callback == callbackToUnbind) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "found callback in service" + authenticatorType);
}
serviceUsers.remove(callbackToUnbind);
if (serviceUsers.isEmpty()) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "there are no more callbacks for service "
+ authenticatorType + ", unbinding service");
}
unbindFromServiceLocked(authenticatorType);
} else {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "leaving service " + authenticatorType
+ " around since there are still callbacks using it");
}
}
return;
}
}
}
Log.e(TAG, "did not find callback " + callbackToUnbind + " in any of the services");
}
}
/**
* You must synchronized on mServiceConnections before calling this
*/
private void unbindFromServiceLocked(String authenticatorType) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "unbindService from " + authenticatorType);
}
mContext.unbindService(mServiceConnections.get(authenticatorType));
mServiceUsers.remove(authenticatorType);
mServiceConnections.remove(authenticatorType);
}
private class ConnectedMessagePayload {
public final IBinder mService;
public final Callback mCallback;
public ConnectedMessagePayload(IBinder service, Callback callback) {
mService = service;
mCallback = callback;
}
}
private class MyServiceConnection implements ServiceConnection {
private final String mAuthenticatorType;
private IBinder mService = null;
public MyServiceConnection(String authenticatorType) {
mAuthenticatorType = authenticatorType;
}
public void onServiceConnected(ComponentName name, IBinder service) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "onServiceConnected for account type " + mAuthenticatorType);
}
// post a message for each service user to tell them that the service is connected
synchronized (mServiceConnections) {
mService = service;
for (Callback callback : mServiceUsers.get(mAuthenticatorType)) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "the service became connected, scheduling a connected "
+ "message for " + mAuthenticatorType);
}
scheduleCallbackConnectedMessage(callback);
}
}
}
private void scheduleCallbackConnectedMessage(Callback callback) {
final ConnectedMessagePayload payload =
new ConnectedMessagePayload(mService, callback);
mHandler.obtainMessage(mMessageWhatConnected, payload).sendToTarget();
}
public void onServiceDisconnected(ComponentName name) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "onServiceDisconnected for account type " + mAuthenticatorType);
}
// post a message for each service user to tell them that the service is disconnected,
// and unbind from the service.
synchronized (mServiceConnections) {
final ArrayList<Callback> callbackList = mServiceUsers.get(mAuthenticatorType);
if (callbackList != null) {
for (Callback callback : callbackList) {
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "the service became disconnected, scheduling a "
+ "disconnected message for "
+ mAuthenticatorType);
}
mHandler.obtainMessage(mMessageWhatDisconnected, callback).sendToTarget();
}
unbindFromServiceLocked(mAuthenticatorType);
}
}
}
}
boolean handleMessage(Message message) {
if (message.what == mMessageWhatConnected) {
ConnectedMessagePayload payload = (ConnectedMessagePayload)message.obj;
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "notifying callback " + payload.mCallback + " that it is connected");
}
payload.mCallback.onConnected(payload.mService);
return true;
} else if (message.what == mMessageWhatDisconnected) {
Callback callback = (Callback)message.obj;
if (Log.isLoggable(TAG, Log.VERBOSE)) {
Log.v(TAG, "notifying callback " + callback + " that it is disconnected");
}
callback.onDisconnected();
return true;
} else {
return false;
}
}
}