Merge "First pass at FingerprintService integration with HAL. Move FingerprintService to framework services directory Fix merge conflicts."
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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}
|
||||
*
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user