Merge "First pass at FingerprintService integration with HAL. Move FingerprintService to framework services directory Fix merge conflicts."

This commit is contained in:
Jim Miller
2014-06-17 21:11:56 +00:00
committed by Android (Google) Code Review
12 changed files with 685 additions and 333 deletions

View File

@@ -26020,29 +26020,61 @@ package android.service.dreams {
package android.service.fingerprint {
public class FingerprintManager {
ctor public FingerprintManager(android.content.Context);
ctor public FingerprintManager(android.content.Context, android.service.fingerprint.IFingerprintService);
method public void enroll(long);
method public void enrollCancel();
method public boolean enrolledAndEnabled();
method public void remove(int);
method public void startListening(android.service.fingerprint.FingerprintManagerReceiver);
method public void stopListening();
field public static final int FINGERPRINT_ACQUIRED = 1; // 0x1
field public static final int FINGERPRINT_ACQUIRED_GOOD = 0; // 0x0
field public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 4; // 0x4
field public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2; // 0x2
field public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1; // 0x1
field public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 16; // 0x10
field public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 8; // 0x8
field public static final int FINGERPRINT_ERROR = -1; // 0xffffffff
field public static final int FINGERPRINT_ERROR_BAD_CAPTURE = 2; // 0x2
field public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1; // 0x1
field public static final int FINGERPRINT_ERROR_NO_RECEIVER = -10; // 0xfffffff6
field public static final int FINGERPRINT_ERROR_NO_SPACE = 4; // 0x4
field public static final int FINGERPRINT_ERROR_TIMEOUT = 3; // 0x3
field public static final int FINGERPRINT_SCANNED = 1; // 0x1
field public static final int FINGERPRINT_TEMPLATE_ENROLLING = 2; // 0x2
field public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2; // 0x2
field public static final int FINGERPRINT_PROCESSED = 2; // 0x2
field public static final int FINGERPRINT_TEMPLATE_ENROLLING = 3; // 0x3
field public static final int FINGERPRINT_TEMPLATE_REMOVED = 4; // 0x4
}
public class FingerprintManagerReceiver {
ctor public FingerprintManagerReceiver();
method public void onAcquired(int);
method public void onEnrollResult(int, int);
method public void onError(int);
method public void onProcessed(int);
method public void onRemoved(int);
method public void onScanned(int, int);
}
public class FingerprintUtils {
ctor public FingerprintUtils();
method public static void addFingerprintIdForUser(int, android.content.ContentResolver, int);
method public static int[] getFingerprintIdsForUser(android.content.ContentResolver, int);
method public static boolean removeFingerprintIdForUser(int, android.content.ContentResolver, int);
}
public abstract interface IFingerprintService implements android.os.IInterface {
method public abstract void enroll(android.os.IBinder, long, int) throws android.os.RemoteException;
method public abstract void enrollCancel(android.os.IBinder, int) throws android.os.RemoteException;
method public abstract void remove(android.os.IBinder, int, int) throws android.os.RemoteException;
method public abstract void startListening(android.os.IBinder, android.service.fingerprint.IFingerprintServiceReceiver, int) throws android.os.RemoteException;
method public abstract void stopListening(android.os.IBinder, int) throws android.os.RemoteException;
}
public abstract interface IFingerprintServiceReceiver implements android.os.IInterface {
method public abstract void onAcquired(int) throws android.os.RemoteException;
method public abstract void onEnrollResult(int, int) throws android.os.RemoteException;
method public abstract void onError(int) throws android.os.RemoteException;
method public abstract void onProcessed(int) throws android.os.RemoteException;
method public abstract void onRemoved(int) throws android.os.RemoteException;
}
}

View File

@@ -115,9 +115,8 @@ import android.os.storage.IMountService;
import android.os.storage.StorageManager;
import android.print.IPrintManager;
import android.print.PrintManager;
import android.service.fingerprint.IFingerprintService;
import android.service.fingerprint.FingerprintManager;
import android.service.fingerprint.FingerprintManagerReceiver;
import android.service.fingerprint.FingerprintService;
import android.telecomm.TelecommManager;
import android.telephony.TelephonyManager;
import android.content.ClipboardManager;
@@ -466,11 +465,6 @@ class ContextImpl extends Context {
return new KeyguardManager();
}});
registerService(FINGERPRINT_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
return new FingerprintManager(ctx);
}});
registerService(LAYOUT_INFLATER_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
return PolicyManager.makeNewLayoutInflater(ctx.getOuterContext());
@@ -690,6 +684,7 @@ class ContextImpl extends Context {
return new MediaSessionManager(ctx);
}
});
registerService(TRUST_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(TRUST_SERVICE);
@@ -697,6 +692,14 @@ class ContextImpl extends Context {
}
});
registerService(FINGERPRINT_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
IBinder b = ServiceManager.getService(FINGERPRINT_SERVICE);
IFingerprintService service = IFingerprintService.Stub.asInterface(b);
return new FingerprintManager(ctx.getOuterContext(), service);
}
});
registerService(TV_INPUT_SERVICE, new ServiceFetcher() {
public Object createService(ContextImpl ctx) {
IBinder iBinder = ServiceManager.getService(TV_INPUT_SERVICE);

View File

@@ -22,12 +22,14 @@ import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Binder;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
import android.provider.Settings;
import android.util.Log;
import android.util.Slog;
/**
* A class that coordinates access to the fingerprint hardware.
@@ -36,31 +38,40 @@ import android.util.Log;
public class FingerprintManager {
private static final String TAG = "FingerprintManager";
private static final boolean DEBUG = true;
private static final String FINGERPRINT_SERVICE_PACKAGE = "com.android.service.fingerprint";
private static final String FINGERPRINT_SERVICE_CLASS =
"com.android.service.fingerprint.FingerprintService";
private static final int MSG_ENROLL_RESULT = 100;
private static final int MSG_SCANNED = 101;
private static final int MSG_ERROR = 102;
private static final int MSG_REMOVED = 103;
private static final int MSG_ACQUIRED = 101;
private static final int MSG_PROCESSED = 102;
private static final int MSG_ERROR = 103;
private static final int MSG_REMOVED = 104;
// Errors generated by layers above HAL
public static final int FINGERPRINT_ERROR_NO_RECEIVER = -10;
public static final int FINGERPRINT_ERROR = -1; // One of the error messages below.
// Progress messages.
public static final int FINGERPRINT_SCANNED = 1;
public static final int FINGERPRINT_TEMPLATE_ENROLLING = 2;
// Message types. Must agree with HAL (fingerprint.h)
public static final int FINGERPRINT_ERROR = -1;
public static final int FINGERPRINT_ACQUIRED = 1;
public static final int FINGERPRINT_PROCESSED = 2;
public static final int FINGERPRINT_TEMPLATE_ENROLLING = 3;
public static final int FINGERPRINT_TEMPLATE_REMOVED = 4;
// Error messages. Must agree with fingerprint HAL definitions.
// Error messages. Must agree with HAL (fingerprint.h)
public static final int FINGERPRINT_ERROR_HW_UNAVAILABLE = 1;
public static final int FINGERPRINT_ERROR_BAD_CAPTURE = 2;
public static final int FINGERPRINT_ERROR_UNABLE_TO_PROCESS = 2;
public static final int FINGERPRINT_ERROR_TIMEOUT = 3;
public static final int FINGERPRINT_ERROR_NO_SPACE = 4;
// FINGERPRINT_ACQUIRED messages. Must agree with HAL (fingerprint.h)
public static final int FINGERPRINT_ACQUIRED_GOOD = 0;
public static final int FINGERPRINT_ACQUIRED_PARTIAL = 1;
public static final int FINGERPRINT_ACQUIRED_INSUFFICIENT = 2;
public static final int FINGERPRINT_ACQUIRED_IMAGER_DIRTY = 4;
public static final int FINGERPRINT_ACQUIRED_TOO_SLOW = 8;
public static final int FINGERPRINT_ACQUIRED_TOO_FAST = 16;
private IFingerprintService mService;
private FingerprintManagerReceiver mClientReceiver;
private Context mContext;
private IBinder mToken = new Binder();
private Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
@@ -69,8 +80,11 @@ public class FingerprintManager {
case MSG_ENROLL_RESULT:
mClientReceiver.onEnrollResult(msg.arg1, msg.arg2);
break;
case MSG_SCANNED:
mClientReceiver.onScanned(msg.arg1, msg.arg2);
case MSG_ACQUIRED:
mClientReceiver.onAcquired(msg.arg1);
break;
case MSG_PROCESSED:
mClientReceiver.onProcessed(msg.arg1);
break;
case MSG_ERROR:
mClientReceiver.onError(msg.arg1);
@@ -82,45 +96,26 @@ public class FingerprintManager {
}
};
public FingerprintManager(Context context) {
public FingerprintManager(Context context, IFingerprintService service) {
mContext = context;
// Connect to service...
Intent intent = new Intent();
intent.setClassName(FINGERPRINT_SERVICE_PACKAGE, FINGERPRINT_SERVICE_CLASS);
if (!context.bindServiceAsUser(intent, mFingerprintConnection,
Context.BIND_AUTO_CREATE, UserHandle.CURRENT_OR_SELF)) {
if (DEBUG) Log.v(TAG, "Can't bind to " + FINGERPRINT_SERVICE_CLASS);
mService = service;
if (mService == null) {
Slog.v(TAG, "FingerprintManagerService was null");
}
}
private final ServiceConnection mFingerprintConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
if (DEBUG) Log.v(TAG, "Connected to FingerprintService");
mService = IFingerprintService.Stub.asInterface(service);
try {
mService.startListening(mServiceReceiver, getCurrentUserId());
} catch (RemoteException e) {
if (DEBUG) Log.v(TAG, "Failed to set callback", e);
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
if (DEBUG) Log.v(TAG, "Disconnected from FingerprintService");
mService = null;
}
};
private IFingerprintServiceReceiver mServiceReceiver = new IFingerprintServiceReceiver.Stub() {
public void onEnrollResult(int fingerprintId, int remaining) {
mHandler.obtainMessage(MSG_ENROLL_RESULT, fingerprintId, remaining).sendToTarget();
}
public void onScanned(int fingerprintId, int confidence) {
mHandler.obtainMessage(MSG_SCANNED, fingerprintId, confidence)
.sendToTarget();;
public void onAcquired(int acquireInfo) {
mHandler.obtainMessage(MSG_ACQUIRED, acquireInfo, 0).sendToTarget();
}
public void onProcessed(int fingerprintId) {
mHandler.obtainMessage(MSG_PROCESSED, fingerprintId, 0).sendToTarget();
}
public void onError(int error) {
@@ -151,12 +146,14 @@ public class FingerprintManager {
*/
public void enroll(long timeout) {
if (mServiceReceiver == null) {
throw new IllegalStateException("enroll: Call registerCallback() first");
sendError(FINGERPRINT_ERROR_NO_RECEIVER, 0, 0);
return;
}
if (mService != null) try {
mService.enroll(timeout, getCurrentUserId());
mService.enroll(mToken, timeout, getCurrentUserId());
} catch (RemoteException e) {
Log.v(TAG, "Remote exception while enrolling: ", e);
sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
}
}
@@ -166,10 +163,19 @@ public class FingerprintManager {
* @param fingerprintId
*/
public void remove(int fingerprintId) {
if (mService != null) try {
mService.remove(fingerprintId, getCurrentUserId());
} catch (RemoteException e) {
Log.v(TAG, "Remote exception during remove of fingerprintId: " + fingerprintId, e);
if (mServiceReceiver == null) {
sendError(FINGERPRINT_ERROR_NO_RECEIVER, 0, 0);
return;
}
if (mService != null) {
try {
mService.remove(mToken, fingerprintId, getCurrentUserId());
} catch (RemoteException e) {
Log.v(TAG, "Remote exception during remove of fingerprintId: " + fingerprintId, e);
}
} else {
Log.w(TAG, "remove(): Service not connected!");
sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
}
}
@@ -181,10 +187,13 @@ public class FingerprintManager {
mClientReceiver = receiver;
if (mService != null) {
try {
mService.startListening(mServiceReceiver, getCurrentUserId());
mService.startListening(mToken, mServiceReceiver, getCurrentUserId());
} catch (RemoteException e) {
Log.v(TAG, "Remote exception in startListening(): ", e);
}
} else {
Log.w(TAG, "startListening(): Service not connected!");
sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
}
}
@@ -201,15 +210,38 @@ public class FingerprintManager {
* Stops the client from listening to fingerprint events.
*/
public void stopListening() {
mClientReceiver = null;
if (mService != null) {
try {
mService.stopListening(getCurrentUserId());
mService.stopListening(mToken, getCurrentUserId());
mClientReceiver = null;
} catch (RemoteException e) {
Log.v(TAG, "Remote exception in stopListening(): ", e);
}
} else {
Log.w(TAG, "stopListening(): Service not connected!");
sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
}
}
public void enrollCancel() {
if (mServiceReceiver == null) {
sendError(FINGERPRINT_ERROR_NO_RECEIVER, 0, 0);
return;
}
if (mService != null) {
try {
mService.enrollCancel(mToken, getCurrentUserId());
mClientReceiver = null;
} catch (RemoteException e) {
Log.v(TAG, "Remote exception in enrollCancel(): ", e);
sendError(FINGERPRINT_ERROR_HW_UNAVAILABLE, 0, 0);
}
} else {
Log.w(TAG, "enrollCancel(): Service not connected!");
}
}
private void sendError(int msg, int arg1, int arg2) {
mHandler.obtainMessage(msg, arg1, arg2);
}
}

View File

@@ -30,18 +30,32 @@ public class FingerprintManagerReceiver {
public void onEnrollResult(int fingerprintId, int remaining) { }
/**
* Fingerprint scan detected. Most clients will use this function to detect a fingerprint
* Fingerprint touch detected, but not processed yet. Clients will use this message to
* determine a good or bad scan before the fingerprint is processed. This is meant for the
* client to provide feedback about the scan or alert the user that recognition is to follow.
*
* @param fingerprintId is the finger the hardware has detected.
* @param confidence from 0 (no confidence) to 65535 (high confidence). Fingerprint 0 has
* special meaning - the finger wasn't recognized.
* @param acquiredInfo one of:
* {@link FingerprintManager#FINGERPRINT_ACQUIRED_GOOD},
* {@link FingerprintManager#FINGERPRINT_ACQUIRED_PARTIAL},
* {@link FingerprintManager#FINGERPRINT_ACQUIRED_INSUFFICIENT},
* {@link FingerprintManager#FINGERPRINT_ACQUIRED_IMAGER_DIRTY},
* {@link FingerprintManager#FINGERPRINT_ACQUIRED_TOO_SLOW},
* {@link FingerprintManager#FINGERPRINT_ACQUIRED_TOO_FAST}
*/
public void onScanned(int fingerprintId, int confidence) { }
public void onAcquired(int acquiredInfo) { }
/**
* Fingerprint has been detected and processed. A non-zero return indicates a valid
* fingerprint was detected.
*
* @param fingerprintId the finger id, or 0 if not recognized.
*/
public void onProcessed(int fingerprintId) { }
/**
* An error was detected during scan or enrollment. One of
* {@link FingerprintManager#FINGERPRINT_ERROR_HW_UNAVAILABLE},
* {@link FingerprintManager#FINGERPRINT_ERROR_BAD_CAPTURE} or
* {@link FingerprintManager#FINGERPRINT_ERROR_UNABLE_TO_PROCESS} or
* {@link FingerprintManager#FINGERPRINT_ERROR_TIMEOUT}
* {@link FingerprintManager#FINGERPRINT_ERROR_NO_SPACE}
*

View File

@@ -1,219 +0,0 @@
/**
* Copyright (C) 2014 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.service.fingerprint;
import android.app.Service;
import android.content.ContentResolver;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.RemoteException;
import android.provider.Settings;
import android.util.Slog;
import java.io.PrintWriter;
import java.util.HashMap;
/**
* A service to manage multiple clients that want to access the fingerprint HAL API.
* The service is responsible for maintaining a list of clients and dispatching all
* fingerprint -related events.
*
* @hide
*/
public class FingerprintService extends Service {
private final String TAG = FingerprintService.class.getSimpleName() +
"[" + getClass().getSimpleName() + "]";
private static final boolean DEBUG = true;
HashMap<IFingerprintServiceReceiver, ClientData> mClients =
new HashMap<IFingerprintServiceReceiver, ClientData>();
private static final int MSG_NOTIFY = 10;
Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case MSG_NOTIFY:
handleNotify(msg.arg1, msg.arg2, (Integer) msg.obj);
break;
default:
Slog.w(TAG, "Unknown message:" + msg.what);
}
}
};
private static final int STATE_IDLE = 0;
private static final int STATE_LISTENING = 1;
private static final int STATE_ENROLLING = 2;
private static final int STATE_DELETING = 3;
private static final long MS_PER_SEC = 1000;
private static final class ClientData {
public IFingerprintServiceReceiver receiver;
int state;
int userId;
}
@Override
public final IBinder onBind(Intent intent) {
if (DEBUG) Slog.v(TAG, "onBind() intent = " + intent);
return new FingerprintServiceWrapper();
}
// JNI methods to communicate from FingerprintManagerService to HAL
native int nativeEnroll(int timeout);
native int nativeRemove(int fingerprintId);
// JNI methods for communicating from HAL to clients
void notify(int msg, int arg1, int arg2) {
mHandler.obtainMessage(MSG_NOTIFY, msg, arg1, arg2).sendToTarget();
}
void handleNotify(int msg, int arg1, int arg2) {
for (int i = 0; i < mClients.size(); i++) {
ClientData clientData = mClients.get(i);
switch (msg) {
case FingerprintManager.FINGERPRINT_ERROR: {
if (clientData.state != STATE_IDLE) {
// FINGERPRINT_ERROR_HW_UNAVAILABLE
// FINGERPRINT_ERROR_BAD_CAPTURE
// FINGERPRINT_ERROR_TIMEOUT
// FINGERPRINT_ERROR_NO_SPACE
final int error = arg1;
clientData.state = STATE_IDLE;
if (clientData.receiver != null) {
try {
clientData.receiver.onError(error);
} catch (RemoteException e) {
Slog.e(TAG, "can't send message to client. Did it die?", e);
}
}
}
}
break;
case FingerprintManager.FINGERPRINT_SCANNED: {
final int fingerId = arg1;
final int confidence = arg2;
if (clientData.state == STATE_LISTENING && clientData.receiver != null) {
try {
clientData.receiver.onScanned(fingerId, confidence);
} catch (RemoteException e) {
Slog.e(TAG, "can't send message to client. Did it die?", e);
}
}
break;
}
case FingerprintManager.FINGERPRINT_TEMPLATE_ENROLLING: {
if (clientData.state == STATE_ENROLLING) {
final int fingerId = arg1;
final int remaining = arg2;
if (remaining == 0) {
FingerprintUtils.addFingerprintIdForUser(fingerId,
getContentResolver(), clientData.userId);
clientData.state = STATE_IDLE; // Nothing left to do
}
if (clientData.receiver != null) {
try {
clientData.receiver.onEnrollResult(fingerId, remaining);
} catch (RemoteException e) {
Slog.e(TAG, "can't send message to client. Did it die?", e);
}
}
}
break;
}
case FingerprintManager.FINGERPRINT_TEMPLATE_REMOVED: {
int fingerId = arg1;
if (fingerId == 0) throw new IllegalStateException("Got illegal id from HAL");
if (clientData.state == STATE_DELETING) {
FingerprintUtils.removeFingerprintIdForUser(fingerId, getContentResolver(),
clientData.userId);
if (clientData.receiver != null) {
try {
clientData.receiver.onRemoved(fingerId);
} catch (RemoteException e) {
Slog.e(TAG, "can't send message to client. Did it die?", e);
}
}
}
}
break;
}
}
}
int enroll(IFingerprintServiceReceiver receiver, long timeout, int userId) {
ClientData clientData = mClients.get(receiver);
if (clientData != null) {
if (clientData.userId != userId) throw new IllegalStateException("Bad user");
clientData.state = STATE_ENROLLING;
return nativeEnroll((int) (timeout / MS_PER_SEC));
}
return -1;
}
int remove(IFingerprintServiceReceiver receiver, int fingerId, int userId) {
ClientData clientData = mClients.get(receiver);
if (clientData != null) {
if (clientData.userId != userId) throw new IllegalStateException("Bad user");
clientData.state = STATE_DELETING;
// The fingerprint id will be removed when we get confirmation from the HAL
return nativeRemove(fingerId);
}
return -1;
}
void startListening(IFingerprintServiceReceiver receiver, int userId) {
ClientData clientData = new ClientData();
clientData.state = STATE_LISTENING;
clientData.receiver = receiver;
clientData.userId = userId;
mClients.put(receiver, clientData);
}
void stopListening(IFingerprintServiceReceiver receiver, int userId) {
ClientData clientData = mClients.get(receiver);
if (clientData != null) {
clientData.state = STATE_IDLE;
clientData.userId = -1;
clientData.receiver = null;
}
mClients.remove(receiver);
}
private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
IFingerprintServiceReceiver mReceiver;
public int enroll(long timeout, int userId) {
return mReceiver != null ? FingerprintService.this.enroll(mReceiver, timeout, userId)
: FingerprintManager.FINGERPRINT_ERROR_NO_RECEIVER;
}
public int remove(int fingerprintId, int userId) {
return FingerprintService.this.remove(mReceiver, fingerprintId, userId);
}
public void startListening(IFingerprintServiceReceiver receiver, int userId) {
mReceiver = receiver;
FingerprintService.this.startListening(receiver, userId);
}
public void stopListening(int userId) {
FingerprintService.this.stopListening(mReceiver, userId);
}
}
}

View File

@@ -18,10 +18,12 @@ package android.service.fingerprint;
import android.content.ContentResolver;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import java.util.Arrays;
public
class FingerprintUtils {
private static final boolean DEBUG = true;
private static final String TAG = "FingerprintUtils";
@@ -30,13 +32,16 @@ class FingerprintUtils {
String fingerIdsRaw = Settings.Secure.getStringForUser(res,
Settings.Secure.USER_FINGERPRINT_IDS, userId);
String[] fingerStringIds = fingerIdsRaw.replace("[","").replace("]","").split(", ");
int result[] = new int[fingerStringIds.length];
for (int i = 0; i < result.length; i++) {
try {
result[i] = Integer.decode(fingerStringIds[i]);
} catch (NumberFormatException e) {
if (DEBUG) Log.d(TAG, "Error when parsing finger id " + fingerStringIds[i]);
int result[] = {};
if (!TextUtils.isEmpty(fingerIdsRaw)) {
String[] fingerStringIds = fingerIdsRaw.replace("[","").replace("]","").split(", ");
result = new int[fingerStringIds.length];
for (int i = 0; i < result.length; i++) {
try {
result[i] = Integer.decode(fingerStringIds[i]);
} catch (NumberFormatException e) {
if (DEBUG) Log.d(TAG, "Error when parsing finger id " + fingerStringIds[i]);
}
}
}
return result;

View File

@@ -22,17 +22,20 @@ import android.service.fingerprint.IFingerprintServiceReceiver;
* Communication channel from client to the fingerprint service.
* @hide
*/
interface IFingerprintService {
// Returns 0 if successfully started, -1 otherwise
int enroll(long timeout, int userId);
oneway interface IFingerprintService {
// Any errors resulting from this call will be returned to the listener
void enroll(IBinder token, long timeout, int userId);
// Any errors resulting from this call will be returned to the listener
void enrollCancel(IBinder token, int userId);
// Returns 0 if fingerprintId's template can be removed, -1 otherwise
int remove(int fingerprintId, int userId);
// Any errors resulting from this call will be returned to the listener
void remove(IBinder token, int fingerprintId, int userId);
// Start listening for fingerprint events. This has the side effect of starting
// the hardware if not already started.
oneway void startListening(IFingerprintServiceReceiver receiver, int userId);
void startListening(IBinder token, IFingerprintServiceReceiver receiver, int userId);
// Stops listening for fingerprints
oneway void stopListening(int userId);
void stopListening(IBinder token, int userId);
}

View File

@@ -24,7 +24,8 @@ import android.os.UserHandle;
*/
oneway interface IFingerprintServiceReceiver {
void onEnrollResult(int fingerprintId, int remaining);
void onScanned(int fingerprintId, int confidence);
void onAcquired(int acquiredInfo);
void onProcessed(int fingerprintId);
void onError(int error);
void onRemoved(int fingerprintId);
}

View File

@@ -159,6 +159,7 @@ extern int register_android_net_TrafficStats(JNIEnv* env);
extern int register_android_text_AndroidCharacter(JNIEnv *env);
extern int register_android_text_AndroidBidi(JNIEnv *env);
extern int register_android_opengl_classes(JNIEnv *env);
extern int register_android_server_fingerprint_FingerprintService(JNIEnv* env);
extern int register_android_server_NetworkManagementSocketTagger(JNIEnv* env);
extern int register_android_server_Watchdog(JNIEnv* env);
extern int register_android_ddm_DdmHandleNativeHeap(JNIEnv *env);
@@ -1328,6 +1329,7 @@ static const RegJNIRec gRegJNI[] = {
REG_JNI(register_android_media_ToneGenerator),
REG_JNI(register_android_opengl_classes),
REG_JNI(register_android_server_fingerprint_FingerprintService),
REG_JNI(register_android_server_NetworkManagementSocketTagger),
REG_JNI(register_android_server_Watchdog),
REG_JNI(register_android_ddm_DdmHandleNativeHeap),

View File

@@ -20,30 +20,10 @@
#include <android_runtime/AndroidRuntime.h>
#include <android_runtime/Log.h>
#include <hardware/hardware.h>
#include <hardware/fingerprint.h>
#include <utils/Log.h>
namespace android {
static struct {
jclass clazz;
jmethodID notify;
} gFingerprintManagerClassInfo;
static jint nativeEnroll(JNIEnv* env, jobject clazz, jint timeout) {
return -1; // TODO
}
static jint nativeRemove(JNIEnv* env, jobject clazz, jint fingerprintId) {
return -1; // TODO
}
// ----------------------------------------------------------------------------
static const JNINativeMethod g_methods[] = {
{ "nativeEnroll", "(I)I", (void*)nativeEnroll },
{ "nativeRemove", "(I)I", (void*)nativeRemove },
};
#define FIND_CLASS(var, className) \
var = env->FindClass(className); \
LOG_FATAL_IF(! var, "Unable to find class " className); \
@@ -61,13 +41,174 @@ static const JNINativeMethod g_methods[] = {
var = env->GetFieldID(clazz, fieldName, fieldDescriptor); \
LOG_FATAL_IF(! var, "Unable to find field " fieldName);
int register_android_server_FingerprintManager(JNIEnv* env) {
FIND_CLASS(gFingerprintManagerClassInfo.clazz,
"android/service/fingerprint/FingerprintManager");
GET_METHOD_ID(gFingerprintManagerClassInfo.notify, gFingerprintManagerClassInfo.clazz,
"notify", "(III)V");
return AndroidRuntime::registerNativeMethods(
env, "com/android/service/fingerprint/FingerprintManager", g_methods, NELEM(g_methods));
namespace android {
static const uint16_t kVersion = HARDWARE_MODULE_API_VERSION(1, 0);
static const char* FINGERPRINT_SERVICE = "com/android/server/fingerprint/FingerprintService";
static struct {
jclass clazz;
jmethodID notify;
jobject callbackObject;
} gFingerprintServiceClassInfo;
static struct {
fingerprint_module_t const* module;
fingerprint_device_t *device;
} gContext;
// TODO: remove after driver update to use new HAL
fingerprint_msg_type_t hackTilFpDriverUpdate(fingerprint_msg_type_t t) {
switch(static_cast<int>(t)) {
case 1: return FINGERPRINT_PROCESSED;
case 2: return FINGERPRINT_TEMPLATE_ENROLLING;
default: return t;
}
}
// Called by the HAL to notify us of fingerprint events
static void hal_notify_callback(fingerprint_msg_t msg) {
uint32_t arg1 = 0;
uint32_t arg2 = 0;
uint32_t arg3 = 0; // TODO
msg.type = hackTilFpDriverUpdate(msg.type);
switch (msg.type) {
case FINGERPRINT_ERROR:
arg1 = msg.data.error;
break;
case FINGERPRINT_ACQUIRED:
arg1 = msg.data.acquired.acquired_info;
break;
case FINGERPRINT_PROCESSED:
arg1 = msg.data.processed.id;
break;
case FINGERPRINT_TEMPLATE_ENROLLING:
arg1 = msg.data.enroll.id;
arg2 = msg.data.enroll.samples_remaining;
arg3 = msg.data.enroll.data_collected_bmp;
break;
case FINGERPRINT_TEMPLATE_REMOVED:
arg1 = msg.data.removed.id;
break;
default:
ALOGE("fingerprint: invalid msg: %d", msg.type);
return;
}
//ALOG(LOG_VERBOSE, LOG_TAG, "hal_notify(msg=%d, arg1=%d, arg2=%d)\n", msg.type, arg1, arg2);
// TODO: fix gross hack to attach JNI to calling thread
JNIEnv* env = AndroidRuntime::getJNIEnv();
if (env == NULL) {
JavaVMAttachArgs args = {JNI_VERSION_1_4, NULL, NULL};
JavaVM* vm = AndroidRuntime::getJavaVM();
int result = vm->AttachCurrentThread(&env, (void*) &args);
if (result != JNI_OK) {
ALOGE("Can't call JNI method: attach failed: %#x", result);
return;
}
}
env->CallVoidMethod(gFingerprintServiceClassInfo.callbackObject,
gFingerprintServiceClassInfo.notify, msg.type, arg1, arg2);
}
static void nativeInit(JNIEnv *env, jobject clazz, jobject callbackObj) {
ALOG(LOG_VERBOSE, LOG_TAG, "nativeInit()\n");
FIND_CLASS(gFingerprintServiceClassInfo.clazz, FINGERPRINT_SERVICE);
GET_METHOD_ID(gFingerprintServiceClassInfo.notify, gFingerprintServiceClassInfo.clazz,
"notify", "(III)V");
gFingerprintServiceClassInfo.callbackObject = env->NewGlobalRef(callbackObj);
}
static jint nativeEnroll(JNIEnv* env, jobject clazz, jint timeout) {
ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnroll()\n");
int ret = gContext.device->enroll(gContext.device, timeout);
return reinterpret_cast<jint>(ret);
}
static jint nativeEnrollCancel(JNIEnv* env, jobject clazz) {
ALOG(LOG_VERBOSE, LOG_TAG, "nativeEnrollCancel()\n");
int ret = gContext.device->enroll_cancel(gContext.device);
return reinterpret_cast<jint>(ret);
}
static jint nativeRemove(JNIEnv* env, jobject clazz, jint fingerprintId) {
ALOG(LOG_VERBOSE, LOG_TAG, "nativeRemove(%d)\n", fingerprintId);
int ret = gContext.device->remove(gContext.device, fingerprintId);
return reinterpret_cast<jint>(ret);
}
static jint nativeOpenHal(JNIEnv* env, jobject clazz) {
ALOG(LOG_VERBOSE, LOG_TAG, "nativeOpenHal()\n");
int err;
const hw_module_t *hw_module = NULL;
if (0 != (err = hw_get_module(FINGERPRINT_HARDWARE_MODULE_ID, &hw_module))) {
ALOGE("Can't open fingerprint HW Module, error: %d", err);
return 0;
}
if (NULL == hw_module) {
ALOGE("No valid fingerprint module");
return 0;
}
gContext.module = reinterpret_cast<const fingerprint_module_t*>(hw_module);
if (gContext.module->common.methods->open == NULL) {
ALOGE("No valid open method");
return 0;
}
hw_device_t *device = NULL;
if (0 != (err = gContext.module->common.methods->open(hw_module, NULL, &device))) {
ALOGE("Can't open fingerprint methods, error: %d", err);
return 0;
}
if (kVersion != device->version) {
ALOGE("Wrong fp version. Expected %d, got %d", kVersion, device->version);
// return 0; // FIXME
}
gContext.device = reinterpret_cast<fingerprint_device_t*>(device);
err = gContext.device->set_notify(gContext.device, hal_notify_callback);
if (err < 0) {
ALOGE("Failed in call to set_notify(), err=%d", err);
return 0;
}
// Sanity check - remove
if (gContext.device->notify != hal_notify_callback) {
ALOGE("NOTIFY not set properly: %p != %p", gContext.device->notify, hal_notify_callback);
}
ALOG(LOG_VERBOSE, LOG_TAG, "fingerprint HAL successfully initialized");
return reinterpret_cast<jlong>(gContext.device);
}
static jint nativeCloseHal(JNIEnv* env, jobject clazz) {
return -ENOSYS; // TODO
}
// ----------------------------------------------------------------------------
// TODO: clean up void methods
static const JNINativeMethod g_methods[] = {
{ "nativeEnroll", "(I)I", (void*)nativeEnroll },
{ "nativeEnrollCancel", "()I", (void*)nativeEnroll },
{ "nativeRemove", "(I)I", (void*)nativeRemove },
{ "nativeOpenHal", "()I", (void*)nativeOpenHal },
{ "nativeCloseHal", "()I", (void*)nativeCloseHal },
{ "nativeInit", "(Lcom/android/server/fingerprint/FingerprintService;)V", (void*)nativeInit }
};
int register_android_server_fingerprint_FingerprintService(JNIEnv* env) {
FIND_CLASS(gFingerprintServiceClassInfo.clazz, FINGERPRINT_SERVICE);
GET_METHOD_ID(gFingerprintServiceClassInfo.notify, gFingerprintServiceClassInfo.clazz, "notify",
"(III)V");
int result = AndroidRuntime::registerNativeMethods(
env, FINGERPRINT_SERVICE, g_methods, NELEM(g_methods));
ALOG(LOG_VERBOSE, LOG_TAG, "FingerprintManager JNI ready.\n");
return result;
}
} // namespace android

View File

@@ -0,0 +1,328 @@
/**
* Copyright (C) 2014 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.server.fingerprint;
import android.app.Service;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.os.Handler;
import android.os.IBinder;
import android.os.PowerManager;
import android.os.RemoteException;
import android.provider.Settings;
import android.service.fingerprint.FingerprintManager;
import android.util.ArrayMap;
import android.util.Slog;
import com.android.server.SystemService;
import android.service.fingerprint.FingerprintUtils;
import android.service.fingerprint.IFingerprintService;
import android.service.fingerprint.IFingerprintServiceReceiver;
import java.io.PrintWriter;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Map.Entry;
import java.util.Set;
/**
* A service to manage multiple clients that want to access the fingerprint HAL API.
* The service is responsible for maintaining a list of clients and dispatching all
* fingerprint -related events.
*
* @hide
*/
public class FingerprintService extends SystemService {
private final String TAG = "FingerprintService";
private static final boolean DEBUG = true;
private ArrayMap<IBinder, ClientData> mClients = new ArrayMap<IBinder, ClientData>();
private static final int MSG_NOTIFY = 10;
Handler mHandler = new Handler() {
public void handleMessage(android.os.Message msg) {
switch (msg.what) {
case MSG_NOTIFY:
handleNotify(msg.arg1, msg.arg2, (Integer) msg.obj);
break;
default:
Slog.w(TAG, "Unknown message:" + msg.what);
}
}
};
private Context mContext;
private static final int STATE_IDLE = 0;
private static final int STATE_LISTENING = 1;
private static final int STATE_ENROLLING = 2;
private static final int STATE_REMOVING = 3;
private static final long MS_PER_SEC = 1000;
public static final String USE_FINGERPRINT = "android.permission.USE_FINGERPRINT";
public static final String ENROLL_FINGERPRINT = "android.permission.ENROLL_FINGERPRINT";
private static final class ClientData {
public IFingerprintServiceReceiver receiver;
int state;
int userId;
public TokenWatcher tokenWatcher;
IBinder getToken() { return tokenWatcher.getToken(); }
}
private class TokenWatcher implements IBinder.DeathRecipient {
WeakReference<IBinder> token;
TokenWatcher(IBinder token) {
this.token = new WeakReference<IBinder>(token);
}
IBinder getToken() { return token.get(); }
public void binderDied() {
mClients.remove(token);
this.token = null;
}
protected void finalize() throws Throwable {
try {
if (token != null) {
if (DEBUG) Slog.w(TAG, "removing leaked reference: " + token);
mClients.remove(token);
}
} finally {
super.finalize();
}
}
}
public FingerprintService(Context context) {
super(context);
mContext = context;
nativeInit(this);
}
// TODO: Move these into separate process
// JNI methods to communicate from FingerprintManagerService to HAL
native int nativeEnroll(int timeout);
native int nativeEnrollCancel();
native int nativeRemove(int fingerprintId);
native int nativeOpenHal();
native int nativeCloseHal();
native void nativeInit(FingerprintService service);
// JNI methods for communicating from HAL to clients
void notify(int msg, int arg1, int arg2) {
mHandler.obtainMessage(MSG_NOTIFY, msg, arg1, arg2).sendToTarget();
}
void handleNotify(int msg, int arg1, int arg2) {
Slog.v(TAG, "handleNotify(msg=" + msg + ", arg1=" + arg1 + ", arg2=" + arg2 + ")");
for (int i = 0; i < mClients.size(); i++) {
ClientData clientData = mClients.valueAt(i);
if (clientData == null || clientData.receiver == null) {
if (DEBUG) Slog.v(TAG, "clientData at " + i + " is invalid!!");
continue;
}
switch (msg) {
case FingerprintManager.FINGERPRINT_ERROR: {
final int error = arg1;
try {
clientData.receiver.onError(error);
} catch (RemoteException e) {
Slog.e(TAG, "can't send message to client. Did it die?", e);
mClients.remove(mClients.keyAt(i));
}
}
break;
case FingerprintManager.FINGERPRINT_ACQUIRED: {
final int acquireInfo = arg1;
try {
clientData.receiver.onAcquired(acquireInfo);
} catch (RemoteException e) {
Slog.e(TAG, "can't send message to client. Did it die?", e);
mClients.remove(mClients.keyAt(i));
}
break;
}
case FingerprintManager.FINGERPRINT_PROCESSED: {
final int fingerId = arg1;
try {
clientData.receiver.onProcessed(fingerId);
} catch (RemoteException e) {
Slog.e(TAG, "can't send message to client. Did it die?", e);
mClients.remove(mClients.keyAt(i));
}
break;
}
case FingerprintManager.FINGERPRINT_TEMPLATE_ENROLLING: {
final int fingerId = arg1;
final int remaining = arg2;
if (clientData.state == STATE_ENROLLING) {
// Only send enroll updates to clients that are actually enrolling
try {
clientData.receiver.onEnrollResult(fingerId, remaining);
} catch (RemoteException e) {
Slog.e(TAG, "can't send message to client. Did it die?", e);
mClients.remove(mClients.keyAt(i));
}
// Update the database with new finger id.
// TODO: move to client code (Settings)
if (remaining == 0) {
FingerprintUtils.addFingerprintIdForUser(fingerId,
mContext.getContentResolver(), clientData.userId);
clientData.state = STATE_IDLE; // Nothing left to do
}
} else {
if (DEBUG) Slog.w(TAG, "Client not enrolling");
break;
}
break;
}
case FingerprintManager.FINGERPRINT_TEMPLATE_REMOVED: {
int fingerId = arg1;
if (fingerId == 0) throw new IllegalStateException("Got illegal id from HAL");
FingerprintUtils.removeFingerprintIdForUser(fingerId,
mContext.getContentResolver(), clientData.userId);
if (clientData.receiver != null) {
try {
clientData.receiver.onRemoved(fingerId);
} catch (RemoteException e) {
Slog.e(TAG, "can't send message to client. Did it die?", e);
mClients.remove(mClients.keyAt(i));
}
}
clientData.state = STATE_LISTENING;
}
break;
}
}
}
void startEnroll(IBinder token, long timeout, int userId) {
ClientData clientData = mClients.get(token);
if (clientData != null) {
if (clientData.userId != userId) throw new IllegalStateException("Bad user");
clientData.state = STATE_ENROLLING;
nativeEnroll((int) (timeout / MS_PER_SEC));
} else {
Slog.w(TAG, "enroll(): No listener registered");
}
}
void startEnrollCancel(IBinder token, int userId) {
ClientData clientData = mClients.get(token);
if (clientData != null) {
if (clientData.userId != userId) throw new IllegalStateException("Bad user");
clientData.state = STATE_LISTENING;
nativeEnrollCancel();
} else {
Slog.w(TAG, "enrollCancel(): No listener registered");
}
}
// Remove all fingerprints for the given user.
void startRemove(IBinder token, int fingerId, int userId) {
ClientData clientData = mClients.get(token);
if (clientData != null) {
if (clientData.userId != userId) throw new IllegalStateException("Bad user");
clientData.state = STATE_REMOVING;
// The fingerprint id will be removed when we get confirmation from the HAL
int result = nativeRemove(fingerId);
if (result != 0) {
Slog.w(TAG, "Error removing fingerprint with id = " + fingerId);
}
} else {
Slog.w(TAG, "remove(" + token + "): No listener registered");
}
}
void addListener(IBinder token, IFingerprintServiceReceiver receiver, int userId) {
if (DEBUG) Slog.v(TAG, "startListening(" + receiver + ")");
if (mClients.get(token) == null) {
ClientData clientData = new ClientData();
clientData.state = STATE_LISTENING;
clientData.receiver = receiver;
clientData.userId = userId;
clientData.tokenWatcher = new TokenWatcher(token);
try {
token.linkToDeath(clientData.tokenWatcher, 0);
mClients.put(token, clientData);
} catch (RemoteException e) {
Slog.w(TAG, "caught remote exception in linkToDeath: ", e);
}
} else {
if (DEBUG) Slog.v(TAG, "listener already registered for " + token);
}
}
void removeListener(IBinder token, int userId) {
if (DEBUG) Slog.v(TAG, "stopListening(" + token + ")");
ClientData clientData = mClients.get(token);
if (clientData != null) {
token.unlinkToDeath(clientData.tokenWatcher, 0);
mClients.remove(token);
} else {
if (DEBUG) Slog.v(TAG, "listener not registered: " + token);
}
mClients.remove(token);
}
void checkPermission(String permisison) {
// TODO
}
private final class FingerprintServiceWrapper extends IFingerprintService.Stub {
@Override // Binder call
public void enroll(IBinder token, long timeout, int userId) {
checkPermission(ENROLL_FINGERPRINT);
startEnroll(token, timeout, userId);
}
@Override // Binder call
public void enrollCancel(IBinder token,int userId) {
checkPermission(ENROLL_FINGERPRINT);
startEnrollCancel(token, userId);
}
@Override // Binder call
public void remove(IBinder token, int fingerprintId, int userId) {
checkPermission(ENROLL_FINGERPRINT); // TODO: Maybe have another permission
startRemove(token, fingerprintId, userId);
}
@Override // Binder call
public void startListening(IBinder token, IFingerprintServiceReceiver receiver, int userId)
{
checkPermission(USE_FINGERPRINT);
addListener(token, receiver, userId);
}
@Override // Binder call
public void stopListening(IBinder token, int userId) {
checkPermission(USE_FINGERPRINT);
removeListener(token, userId);
}
}
@Override
public void onStart() {
publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
nativeOpenHal();
}
}

View File

@@ -44,6 +44,7 @@ import android.os.SystemClock;
import android.os.SystemProperties;
import android.os.UserHandle;
import android.service.dreams.DreamService;
import android.service.fingerprint.FingerprintManager;
import android.util.DisplayMetrics;
import android.util.EventLog;
import android.util.Log;
@@ -63,6 +64,7 @@ import com.android.server.content.ContentService;
import com.android.server.devicepolicy.DevicePolicyManagerService;
import com.android.server.display.DisplayManagerService;
import com.android.server.dreams.DreamManagerService;
import com.android.server.fingerprint.FingerprintService;
import com.android.server.hdmi.HdmiControlService;
import com.android.server.input.InputManagerService;
import com.android.server.job.JobSchedulerService;
@@ -988,12 +990,20 @@ public final class SystemServer {
Slog.e(TAG, "Failure starting TrustManagerService", e);
}
try {
Slog.i(TAG, "Fingerprint Manager");
mSystemServiceManager.startService(FingerprintService.class);
} catch (Throwable e) {
Slog.e(TAG, "Failure starting FingerprintService", e);
}
try {
Slog.i(TAG, "BackgroundDexOptService");
new BackgroundDexOptService(context);
} catch (Throwable e) {
reportWtf("starting BackgroundDexOptService", e);
}
}
try {