diff options
62 files changed, 2915 insertions, 503 deletions
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c index a33dcf3..5fa437a 100644 --- a/cmds/dumpstate/dumpstate.c +++ b/cmds/dumpstate/dumpstate.c @@ -242,8 +242,6 @@ static void dumpstate() { run_command("LAST LOGCAT", 10, "logcat", "-L", "-v", "threadtime", "-b", "all", "-d", "*:v", NULL); - for_each_userid(do_dump_settings, NULL); - /* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */ run_command("NETWORK INTERFACES", 10, "ip", "link", NULL); diff --git a/cmds/dumpstate/dumpstate.h b/cmds/dumpstate/dumpstate.h index d17a677..8335e26 100644 --- a/cmds/dumpstate/dumpstate.h +++ b/cmds/dumpstate/dumpstate.h @@ -26,7 +26,6 @@ typedef void (for_each_pid_func)(int, const char *); typedef void (for_each_tid_func)(int, int, const char *); -typedef void (for_each_userid_func)(int); /* prints the contents of a file */ int dump_file(const char *title, const char *path); @@ -57,9 +56,6 @@ void for_each_pid(for_each_pid_func func, const char *header); /* for each thread in the system, run the specified function */ void for_each_tid(for_each_tid_func func, const char *header); -/* for each user id in the system, run the specified function */ -void for_each_userid(for_each_userid_func func, const char *header); - /* Displays a blocked processes in-kernel wait channel */ void show_wchan(int pid, int tid, const char *name); @@ -69,9 +65,6 @@ void do_showmap(int pid, const char *name); /* Gets the dmesg output for the kernel */ void do_dmesg(); -/* Dumps settings for a given user id */ -void do_dump_settings(int userid); - /* Prints the contents of all the routing tables, both IPv4 and IPv6. */ void dump_route_tables(); diff --git a/cmds/dumpstate/utils.c b/cmds/dumpstate/utils.c index cf14c8b..3d9a2b5 100644 --- a/cmds/dumpstate/utils.c +++ b/cmds/dumpstate/utils.c @@ -206,22 +206,6 @@ out_close: return; } -void do_dump_settings(int userid) { - char title[255]; - char dbpath[255]; - char sql[255]; - sprintf(title, "SYSTEM SETTINGS (user %d)", userid); - if (userid == 0) { - strcpy(dbpath, "/data/data/com.android.providers.settings/databases/settings.db"); - strcpy(sql, "pragma user_version; select * from system; select * from secure; select * from global;"); - } else { - sprintf(dbpath, "/data/system/users/%d/settings.db", userid); - strcpy(sql, "pragma user_version; select * from system; select * from secure;"); - } - run_command(title, 20, SU_PATH, "root", "sqlite3", dbpath, sql, NULL); - return; -} - void do_dmesg() { printf("------ KERNEL LOG (dmesg) ------\n"); /* Get size of kernel buffer */ diff --git a/cmds/service/service.cpp b/cmds/service/service.cpp index 97fc47c..428b87c 100644 --- a/cmds/service/service.cpp +++ b/cmds/service/service.cpp @@ -146,6 +146,15 @@ int main(int argc, char* const argv[]) break; } data.writeInt32(atoi(argv[optind++])); + } else if (strcmp(argv[optind], "i64") == 0) { + optind++; + if (optind >= argc) { + aerr << "service: no integer supplied for 'i64'" << endl; + wantsUsage = true; + result = 10; + break; + } + data.writeInt64(atoll(argv[optind++])); } else if (strcmp(argv[optind], "s16") == 0) { optind++; if (optind >= argc) { @@ -155,6 +164,24 @@ int main(int argc, char* const argv[]) break; } data.writeString16(String16(argv[optind++])); + } else if (strcmp(argv[optind], "f") == 0) { + optind++; + if (optind >= argc) { + aerr << "service: no number supplied for 'f'" << endl; + wantsUsage = true; + result = 10; + break; + } + data.writeFloat(atof(argv[optind++])); + } else if (strcmp(argv[optind], "d") == 0) { + optind++; + if (optind >= argc) { + aerr << "service: no number supplied for 'd'" << endl; + wantsUsage = true; + result = 10; + break; + } + data.writeDouble(atof(argv[optind++])); } else if (strcmp(argv[optind], "null") == 0) { optind++; data.writeStrongBinder(NULL); @@ -272,9 +299,12 @@ int main(int argc, char* const argv[]) aout << "Usage: service [-h|-?]\n" " service list\n" " service check SERVICE\n" - " service call SERVICE CODE [i32 INT | s16 STR] ...\n" + " service call SERVICE CODE [i32 N | i64 N | f N | d N | s16 STR ] ...\n" "Options:\n" - " i32: Write the integer INT into the send parcel.\n" + " i32: Write the 32-bit integer N into the send parcel.\n" + " i64: Write the 64-bit integer N into the send parcel.\n" + " f: Write the 32-bit single-precision number N into the send parcel.\n" + " d: Write the 64-bit double-precision number N into the send parcel.\n" " s16: Write the UTF-16 string STR into the send parcel.\n"; // " intent: Write and Intent int the send parcel. ARGS can be\n" // " action=STR data=STR type=STR launchFlags=INT component=STR categories=STR[,STR,...]\n"; diff --git a/data/etc/android.hardware.sensor.hifi_sensors.xml b/data/etc/android.hardware.sensor.hifi_sensors.xml new file mode 100644 index 0000000..bb3901c --- /dev/null +++ b/data/etc/android.hardware.sensor.hifi_sensors.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2009 The Android Open Source Project + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +--> + +<!-- Feature for devices supporting hifi sensors. --> +<permissions> + <feature name="android.hardware.sensor.hifi_sensors" /> +</permissions> diff --git a/data/etc/android.software.midi.xml b/data/etc/android.software.midi.xml new file mode 100644 index 0000000..a03cd55 --- /dev/null +++ b/data/etc/android.software.midi.xml @@ -0,0 +1,19 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- Copyright (C) 2015 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. +--> + +<permissions> + <feature name="android.software.midi" /> +</permissions> diff --git a/include/android/keycodes.h b/include/android/keycodes.h index 75d0ab6..80e44c0 100644 --- a/include/android/keycodes.h +++ b/include/android/keycodes.h @@ -302,7 +302,11 @@ enum { AKEYCODE_TV_CONTENTS_MENU = 256, AKEYCODE_TV_MEDIA_CONTEXT_MENU = 257, AKEYCODE_TV_TIMER_PROGRAMMING = 258, - AKEYCODE_HELP = 259 + AKEYCODE_HELP = 259, + AKEYCODE_NAVIGATE_PREVIOUS = 260, + AKEYCODE_NAVIGATE_NEXT = 261, + AKEYCODE_NAVIGATE_IN = 262, + AKEYCODE_NAVIGATE_OUT = 263 // NOTE: If you add a new keycode here you must also add it to several other files. // Refer to frameworks/base/core/java/android/view/KeyEvent.java for the full list. diff --git a/include/android/multinetwork.h b/include/android/multinetwork.h new file mode 100644 index 0000000..6c718c9 --- /dev/null +++ b/include/android/multinetwork.h @@ -0,0 +1,109 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef ANDROID_MULTINETWORK_H +#define ANDROID_MULTINETWORK_H + +#include <netdb.h> +#include <stdlib.h> +#include <sys/cdefs.h> + +__BEGIN_DECLS + +/** + * The corresponding C type for android.net.Network#getNetworkHandle() return + * values. The Java signed long value can be safely cast to a net_handle_t: + * + * [C] ((net_handle_t) java_long_network_handle) + * [C++] static_cast<net_handle_t>(java_long_network_handle) + * + * as appropriate. + */ +typedef uint64_t net_handle_t; + +/** + * The value NETWORK_UNSPECIFIED indicates no specific network. + * + * For some functions (documented below), a previous binding may be cleared + * by an invocation with NETWORK_UNSPECIFIED. + * + * Depending on the context it may indicate an error. It is expressly + * not used to indicate some notion of the "current default network". + */ +#define NETWORK_UNSPECIFIED ((net_handle_t)0) + + +/** + * All functions below that return an int return 0 on success or -1 + * on failure with an appropriate errno value set. + */ + + +/** + * Set the network to be used by the given socket file descriptor. + * + * To clear a previous socket binding invoke with NETWORK_UNSPECIFIED. + * + * This is the equivalent of: + * + * [ android.net.Network#bindSocket() ] + * https://developer.android.com/reference/android/net/Network.html#bindSocket(java.net.Socket) + */ +int android_setsocknetwork(net_handle_t network, int fd); + + +/** + * Binds the current process to |network|. All sockets created in the future + * (and not explicitly bound via android_setsocknetwork()) will be bound to + * |network|. All host name resolutions will be limited to |network| as well. + * Note that if the network identified by |network| ever disconnects, all + * sockets created in this way will cease to work and all host name + * resolutions will fail. This is by design so an application doesn't + * accidentally use sockets it thinks are still bound to a particular network. + * + * To clear a previous process binding invoke with NETWORK_UNSPECIFIED. + * + * This is the equivalent of: + * + * [ android.net.ConnectivityManager#setProcessDefaultNetwork() ] + * https://developer.android.com/reference/android/net/ConnectivityManager.html#setProcessDefaultNetwork(android.net.Network) + */ +int android_setprocnetwork(net_handle_t network); + + +/** + * Perform hostname resolution via the DNS servers associated with |network|. + * + * All arguments (apart from |network|) are used identically as those passed + * to getaddrinfo(3). Return and error values are identical to those of + * getaddrinfo(3), and in particular gai_strerror(3) can be used as expected. + * Similar to getaddrinfo(3): + * - |hints| may be NULL (in which case man page documented defaults apply) + * - either |node| or |service| may be NULL, but not both + * - |res| must not be NULL + * + * This is the equivalent of: + * + * [ android.net.Network#getAllByName() ] + * https://developer.android.com/reference/android/net/Network.html#getAllByName(java.lang.String) + */ +int android_getaddrinfofornetwork(net_handle_t network, + const char *node, const char *service, + const struct addrinfo *hints, struct addrinfo **res); + +__END_DECLS + +#endif // ANDROID_MULTINETWORK_H diff --git a/include/binder/IPCThreadState.h b/include/binder/IPCThreadState.h index 60c2242..1853cff 100644 --- a/include/binder/IPCThreadState.h +++ b/include/binder/IPCThreadState.h @@ -76,14 +76,18 @@ public: BpBinder* proxy); static void shutdown(); - + // Call this to disable switching threads to background scheduling when // receiving incoming IPC calls. This is specifically here for the // Android system process, since it expects to have background apps calling // in to it but doesn't want to acquire locks in its services while in // the background. static void disableBackgroundScheduling(bool disable); - + + // Call blocks until the number of executing binder threads is less than + // the maximum number of binder threads threads allowed for this process. + void blockUntilThreadAvailable(); + private: IPCThreadState(); ~IPCThreadState(); @@ -101,9 +105,9 @@ private: status_t getAndExecuteCommand(); status_t executeCommand(int32_t command); void processPendingDerefs(); - + void clearCaller(); - + static void threadDestructor(void *st); static void freeBuffer(Parcel* parcel, const uint8_t* data, size_t dataSize, @@ -114,7 +118,7 @@ private: const pid_t mMyThreadId; Vector<BBinder*> mPendingStrongDerefs; Vector<RefBase::weakref_type*> mPendingWeakDerefs; - + Parcel mIn; Parcel mOut; status_t mLastError; diff --git a/include/binder/IProcessInfoService.h b/include/binder/IProcessInfoService.h new file mode 100644 index 0000000..dc62f45 --- /dev/null +++ b/include/binder/IProcessInfoService.h @@ -0,0 +1,53 @@ +/* + * Copyright 2015 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. + */ + +#ifndef ANDROID_I_PROCESS_INFO_SERVICE_H +#define ANDROID_I_PROCESS_INFO_SERVICE_H + +#include <binder/IInterface.h> + +namespace android { + +// ---------------------------------------------------------------------- + +class IProcessInfoService : public IInterface { +public: + DECLARE_META_INTERFACE(ProcessInfoService); + + virtual status_t getProcessStatesFromPids( size_t length, + /*in*/ int32_t* pids, + /*out*/ int32_t* states) = 0; + + enum { + GET_PROCESS_STATES_FROM_PIDS = IBinder::FIRST_CALL_TRANSACTION, + }; +}; + +// ---------------------------------------------------------------------- + +class BnProcessInfoService : public BnInterface<IProcessInfoService> { +public: + virtual status_t onTransact( uint32_t code, + const Parcel& data, + Parcel* reply, + uint32_t flags = 0); +}; + +// ---------------------------------------------------------------------- + +}; // namespace android + +#endif // ANDROID_I_PROCESS_INFO_SERVICE_H diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h index a52e044..da960aa 100644 --- a/include/binder/Parcel.h +++ b/include/binder/Parcel.h @@ -96,6 +96,7 @@ public: status_t writeInt32(int32_t val); status_t writeUint32(uint32_t val); status_t writeInt64(int64_t val); + status_t writeUint64(uint64_t val); status_t writeFloat(float val); status_t writeDouble(double val); status_t writeCString(const char* str); @@ -157,6 +158,8 @@ public: status_t readUint32(uint32_t *pArg) const; int64_t readInt64() const; status_t readInt64(int64_t *pArg) const; + uint64_t readUint64() const; + status_t readUint64(uint64_t *pArg) const; float readFloat() const; status_t readFloat(float *pArg) const; double readDouble() const; @@ -334,6 +337,12 @@ public: public: inline void* data() { return mData; } }; + +private: + size_t mBlobAshmemSize; + +public: + size_t getBlobAshmemSize() const; }; // --------------------------------------------------------------------------- diff --git a/include/binder/ProcessInfoService.h b/include/binder/ProcessInfoService.h new file mode 100644 index 0000000..c5ead20 --- /dev/null +++ b/include/binder/ProcessInfoService.h @@ -0,0 +1,65 @@ +/* + * Copyright 2015 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. + */ + +#ifndef ANDROID_PROCESS_INFO_SERVICE_H +#define ANDROID_PROCESS_INFO_SERVICE_H + +#include <binder/IProcessInfoService.h> +#include <utils/Errors.h> +#include <utils/Singleton.h> +#include <sys/types.h> + +namespace android { + +// ---------------------------------------------------------------------- + +class ProcessInfoService : public Singleton<ProcessInfoService> { + + friend class Singleton<ProcessInfoService>; + sp<IProcessInfoService> mProcessInfoService; + Mutex mProcessInfoLock; + + ProcessInfoService(); + + status_t getProcessStatesImpl(size_t length, /*in*/ int32_t* pids, /*out*/ int32_t* states); + void updateBinderLocked(); + + static const int BINDER_ATTEMPT_LIMIT = 5; + +public: + + /** + * For each PID in the given "pids" input array, write the current process state + * for that process into the "states" output array, or + * ActivityManager.PROCESS_STATE_NONEXISTENT * to indicate that no process with the given PID + * exists. + * + * Returns NO_ERROR if this operation was successful, or a negative error code otherwise. + */ + static status_t getProcessStatesFromPids(size_t length, /*in*/ int32_t* pids, + /*out*/ int32_t* states) { + return ProcessInfoService::getInstance().getProcessStatesImpl(length, /*in*/ pids, + /*out*/ states); + } + +}; + +// ---------------------------------------------------------------------- + +}; // namespace android + +#endif // ANDROID_PROCESS_INFO_SERVICE_H + diff --git a/include/binder/ProcessState.h b/include/binder/ProcessState.h index 3bc978d..f9edc2a 100644 --- a/include/binder/ProcessState.h +++ b/include/binder/ProcessState.h @@ -24,6 +24,8 @@ #include <utils/threads.h> +#include <pthread.h> + // --------------------------------------------------------------------------- namespace android { @@ -71,25 +73,33 @@ private: ProcessState(const ProcessState& o); ProcessState& operator=(const ProcessState& o); String8 makeBinderThreadName(); - + struct handle_entry { IBinder* binder; RefBase::weakref_type* refs; }; - + handle_entry* lookupHandleLocked(int32_t handle); int mDriverFD; void* mVMStart; - + + // Protects thread count variable below. + pthread_mutex_t mThreadCountLock; + pthread_cond_t mThreadCountDecrement; + // Number of binder threads current executing a command. + size_t mExecutingThreadsCount; + // Maximum number for binder threads allowed for this process. + size_t mMaxThreads; + mutable Mutex mLock; // protects everything below. - + Vector<handle_entry>mHandleToObject; bool mManagesContexts; context_check_func mBinderContextCheckFunc; void* mBinderContextUserData; - + KeyedVector<String16, sp<IBinder> > mContexts; diff --git a/include/gui/ISensorServer.h b/include/gui/ISensorServer.h index 9c8afc5..ee3484c 100644 --- a/include/gui/ISensorServer.h +++ b/include/gui/ISensorServer.h @@ -30,6 +30,7 @@ namespace android { class Sensor; class ISensorEventConnection; +class String8; class ISensorServer : public IInterface { @@ -37,7 +38,9 @@ public: DECLARE_META_INTERFACE(SensorServer); virtual Vector<Sensor> getSensorList() = 0; - virtual sp<ISensorEventConnection> createSensorEventConnection() = 0; + virtual sp<ISensorEventConnection> createSensorEventConnection(const String8& packageName, + int mode) = 0; + virtual status_t enableDataInjection(int enable) = 0; }; // ---------------------------------------------------------------------------- diff --git a/include/gui/SensorEventQueue.h b/include/gui/SensorEventQueue.h index 02b3d38..b70957b 100644 --- a/include/gui/SensorEventQueue.h +++ b/include/gui/SensorEventQueue.h @@ -77,6 +77,8 @@ public: status_t flush() const; // Send an ack for every wake_up sensor event that is set to WAKE_UP_SENSOR_EVENT_NEEDS_ACK. void sendAck(const ASensorEvent* events, int count); + + status_t injectSensorEvent(const ASensorEvent& event); private: sp<Looper> getLooper() const; sp<ISensorEventConnection> mSensorEventConnection; diff --git a/include/gui/SensorManager.h b/include/gui/SensorManager.h index 3176462..4cabf59 100644 --- a/include/gui/SensorManager.h +++ b/include/gui/SensorManager.h @@ -26,6 +26,7 @@ #include <utils/RefBase.h> #include <utils/Singleton.h> #include <utils/Vector.h> +#include <utils/String8.h> #include <gui/SensorEventQueue.h> @@ -40,7 +41,6 @@ namespace android { class ISensorServer; class Sensor; class SensorEventQueue; - // ---------------------------------------------------------------------------- class SensorManager : @@ -53,7 +53,8 @@ public: ssize_t getSensorList(Sensor const* const** list) const; Sensor const* getDefaultSensor(int type); - sp<SensorEventQueue> createEventQueue(); + sp<SensorEventQueue> createEventQueue(String8 packageName = String8(""), int mode = 0); + status_t enableDataInjection(bool enable); private: // DeathRecipient interface diff --git a/include/input/IInputFlinger.h b/include/input/IInputFlinger.h new file mode 100644 index 0000000..629310f --- /dev/null +++ b/include/input/IInputFlinger.h @@ -0,0 +1,52 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef _LIBINPUT_IINPUT_FLINGER_H +#define _LIBINPUT_IINPUT_FLINGER_H + +#include <stdint.h> +#include <sys/types.h> + +#include <binder/IInterface.h> + +namespace android { + +/* + * This class defines the Binder IPC interface for accessing various + * InputFlinger features. + */ +class IInputFlinger : public IInterface { +public: + DECLARE_META_INTERFACE(InputFlinger); +}; + + +/** + * Binder implementation. + */ +class BnInputFlinger : public BnInterface<IInputFlinger> { +public: + enum { + DO_SOMETHING_TRANSACTION = IBinder::FIRST_CALL_TRANSACTION, + }; + + virtual status_t onTransact(uint32_t code, const Parcel& data, + Parcel* reply, uint32_t flags = 0); +}; + +} // namespace android + +#endif // _LIBINPUT_IINPUT_FLINGER_H diff --git a/include/input/Input.h b/include/input/Input.h index 96b6885..c360f63 100644 --- a/include/input/Input.h +++ b/include/input/Input.h @@ -149,10 +149,22 @@ enum { * NOTE: If you want a flag to be able to set in a keylayout file, then you must add it to * InputEventLabels.h as well. */ + // Indicates that the event should wake the device. POLICY_FLAG_WAKE = 0x00000001, + + // Indicates that the key is virtual, such as a capacitive button, and should + // generate haptic feedback. Virtual keys may be suppressed for some time + // after a recent touch to prevent accidental activation of virtual keys adjacent + // to the touch screen during an edge swipe. POLICY_FLAG_VIRTUAL = 0x00000002, + + // Indicates that the key is the special function modifier. POLICY_FLAG_FUNCTION = 0x00000004, + // Indicates that the key represents a special gesture that has been detected by + // the touch firmware or driver. Causes touch events from the same device to be canceled. + POLICY_FLAG_GESTURE = 0x00000008, + POLICY_FLAG_RAW_MASK = 0x0000ffff, /* These flags are set by the input dispatcher. */ diff --git a/include/input/InputDevice.h b/include/input/InputDevice.h index adf9fb9..1ea69d3 100644 --- a/include/input/InputDevice.h +++ b/include/input/InputDevice.h @@ -73,7 +73,8 @@ public: }; void initialize(int32_t id, int32_t generation, int32_t controllerNumber, - const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal); + const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal, + bool hasMic); inline int32_t getId() const { return mId; } inline int32_t getControllerNumber() const { return mControllerNumber; } @@ -84,6 +85,7 @@ public: return mAlias.isEmpty() ? mIdentifier.name : mAlias; } inline bool isExternal() const { return mIsExternal; } + inline bool hasMic() const { return mHasMic; } inline uint32_t getSources() const { return mSources; } const MotionRange* getMotionRange(int32_t axis, uint32_t source) const; @@ -121,6 +123,7 @@ private: InputDeviceIdentifier mIdentifier; String8 mAlias; bool mIsExternal; + bool mHasMic; uint32_t mSources; int32_t mKeyboardType; sp<KeyCharacterMap> mKeyCharacterMap; diff --git a/include/input/InputEventLabels.h b/include/input/InputEventLabels.h index df50237..3962001 100644 --- a/include/input/InputEventLabels.h +++ b/include/input/InputEventLabels.h @@ -299,6 +299,10 @@ static const InputEventLabel KEYCODES[] = { DEFINE_KEYCODE(TV_MEDIA_CONTEXT_MENU), DEFINE_KEYCODE(TV_TIMER_PROGRAMMING), DEFINE_KEYCODE(HELP), + DEFINE_KEYCODE(NAVIGATE_PREVIOUS), + DEFINE_KEYCODE(NAVIGATE_NEXT), + DEFINE_KEYCODE(NAVIGATE_IN), + DEFINE_KEYCODE(NAVIGATE_OUT), { NULL, 0 } }; @@ -376,6 +380,7 @@ static const InputEventLabel LEDS[] = { static const InputEventLabel FLAGS[] = { DEFINE_FLAG(VIRTUAL), DEFINE_FLAG(FUNCTION), + DEFINE_FLAG(GESTURE), { NULL, 0 } }; diff --git a/include/media/drm/DrmAPI.h b/include/media/drm/DrmAPI.h index 49939fd..272881b 100644 --- a/include/media/drm/DrmAPI.h +++ b/include/media/drm/DrmAPI.h @@ -80,7 +80,10 @@ namespace android { kDrmPluginEventProvisionRequired = 1, kDrmPluginEventKeyNeeded, kDrmPluginEventKeyExpired, - kDrmPluginEventVendorDefined + kDrmPluginEventVendorDefined, + kDrmPluginEventSessionReclaimed, + kDrmPluginEventExpirationUpdate, + kDrmPluginEventKeysChange, }; // Drm keys can be for offline content or for online streaming. @@ -93,6 +96,33 @@ namespace android { kKeyType_Release }; + // Enumerate KeyRequestTypes to allow an app to determine the + // type of a key request returned from getKeyRequest. + enum KeyRequestType { + kKeyRequestType_Unknown, + kKeyRequestType_Initial, + kKeyRequestType_Renewal, + kKeyRequestType_Release + }; + + // Enumerate KeyStatusTypes which indicate the state of a key + enum KeyStatusType + { + kKeyStatusType_Usable, + kKeyStatusType_Expired, + kKeyStatusType_OutputNotAllowed, + kKeyStatusType_StatusPending, + kKeyStatusType_InternalError + }; + + // Used by sendKeysChange to report the usability status of each + // key to the app. + struct KeyStatus + { + Vector<uint8_t> mKeyId; + KeyStatusType mType; + }; + DrmPlugin() {} virtual ~DrmPlugin() {} @@ -135,7 +165,8 @@ namespace android { Vector<uint8_t> const &initData, String8 const &mimeType, KeyType keyType, KeyedVector<String8, String8> const &optionalParameters, - Vector<uint8_t> &request, String8 &defaultUrl) = 0; + Vector<uint8_t> &request, String8 &defaultUrl, + KeyRequestType *keyRequestType) = 0; // // After a key response is received by the app, it is provided to the @@ -315,11 +346,18 @@ namespace android { } protected: - // Plugins call sendEvent to deliver events to the java app + // Plugins call these methods to deliver events to the java app void sendEvent(EventType eventType, int extra, Vector<uint8_t> const *sessionId, Vector<uint8_t> const *data); + void sendExpirationUpdate(Vector<uint8_t> const *sessionId, + int64_t expiryTimeInMS); + + void sendKeysChange(Vector<uint8_t> const *sessionId, + Vector<DrmPlugin::KeyStatus> const *keyStatusList, + bool hasNewUsableKey); + private: Mutex mEventLock; sp<DrmPluginListener> mListener; @@ -331,14 +369,20 @@ namespace android { { public: virtual void sendEvent(DrmPlugin::EventType eventType, int extra, - Vector<uint8_t> const *sesionId, + Vector<uint8_t> const *sessionId, Vector<uint8_t> const *data) = 0; + + virtual void sendExpirationUpdate(Vector<uint8_t> const *sessionId, + int64_t expiryTimeInMS) = 0; + + virtual void sendKeysChange(Vector<uint8_t> const *sessionId, + Vector<DrmPlugin::KeyStatus> const *keyStatusList, + bool hasNewUsableKey) = 0; }; inline void DrmPlugin::sendEvent(EventType eventType, int extra, Vector<uint8_t> const *sessionId, Vector<uint8_t> const *data) { - mEventLock.lock(); sp<DrmPluginListener> listener = mListener; mEventLock.unlock(); @@ -348,6 +392,28 @@ namespace android { } } + inline void DrmPlugin::sendExpirationUpdate(Vector<uint8_t> const *sessionId, + int64_t expiryTimeInMS) { + mEventLock.lock(); + sp<DrmPluginListener> listener = mListener; + mEventLock.unlock(); + + if (listener != NULL) { + listener->sendExpirationUpdate(sessionId, expiryTimeInMS); + } + } + + inline void DrmPlugin::sendKeysChange(Vector<uint8_t> const *sessionId, + Vector<DrmPlugin::KeyStatus> const *keyStatusList, + bool hasNewUsableKey) { + mEventLock.lock(); + sp<DrmPluginListener> listener = mListener; + mEventLock.unlock(); + + if (listener != NULL) { + listener->sendKeysChange(sessionId, keyStatusList, hasNewUsableKey); + } + } } // namespace android #endif // DRM_API_H_ diff --git a/include/media/hardware/CryptoAPI.h b/include/media/hardware/CryptoAPI.h index c800825..3e3257f 100644 --- a/include/media/hardware/CryptoAPI.h +++ b/include/media/hardware/CryptoAPI.h @@ -14,7 +14,9 @@ * limitations under the License. */ +#include <media/stagefright/MediaErrors.h> #include <utils/Errors.h> +#include <utils/Vector.h> #ifndef CRYPTO_API_H_ @@ -68,7 +70,18 @@ struct CryptoPlugin { // the resolution of the video being decrypted. The media player should // call this method when the resolution is determined and any time it // is subsequently changed. - virtual void notifyResolution(uint32_t width, uint32_t height) {} + + virtual void notifyResolution(uint32_t /* width */, uint32_t /* height */) {} + + // A MediaDrm session may be associated with a MediaCrypto session. The + // associated MediaDrm session is used to load decryption keys + // into the crypto/drm plugin. The keys are then referenced by key-id + // in the 'key' parameter to the decrypt() method. + // Should return NO_ERROR on success, ERROR_DRM_SESSION_NOT_OPENED if + // the session is not opened and a code from MediaErrors.h otherwise. + virtual status_t setMediaDrmSession(const Vector<uint8_t> & /*sessionId */) { + return ERROR_UNSUPPORTED; + } // If the error returned falls into the range // ERROR_DRM_VENDOR_MIN..ERROR_DRM_VENDOR_MAX, errorDetailMsg should be diff --git a/include/media/openmax/OMX_AsString.h b/include/media/openmax/OMX_AsString.h index 0f177a1..65eb562 100644 --- a/include/media/openmax/OMX_AsString.h +++ b/include/media/openmax/OMX_AsString.h @@ -287,6 +287,7 @@ inline static const char *asString(OMX_EVENTTYPE i, const char *def = "??") { // case OMX_EventComponentResumed: return "ComponentResumed"; // case OMX_EventDynamicResourcesAvailable: return "DynamicResourcesAvailable"; // case OMX_EventPortFormatDetected: return "PortFormatDetected"; + case OMX_EventOutputRendered: return "OutputRendered"; default: return def; } } @@ -521,6 +522,8 @@ inline static const char *asString(OMX_INDEXEXTTYPE i, const char *def = "??") { case OMX_IndexParamVideoHevc: return "ParamVideoHevc"; // case OMX_IndexParamSliceSegments: return "ParamSliceSegments"; case OMX_IndexConfigAutoFramerateConversion: return "ConfigAutoFramerateConversion"; + case OMX_IndexConfigPriority: return "ConfigPriority"; + case OMX_IndexConfigOperatingRate: return "ConfigOperatingRate"; default: return asString((OMX_INDEXTYPE)i, def); } } diff --git a/include/media/openmax/OMX_Core.h b/include/media/openmax/OMX_Core.h index 12f2b3b..4fc1546 100644 --- a/include/media/openmax/OMX_Core.h +++ b/include/media/openmax/OMX_Core.h @@ -503,12 +503,18 @@ typedef enum OMX_EVENTTYPE OMX_EventResourcesAcquired, /**< component has been granted resources and is automatically starting the state change from OMX_StateWaitForResources to OMX_StateIdle. */ - OMX_EventComponentResumed, /**< Component resumed due to reacquisition of resources */ - OMX_EventDynamicResourcesAvailable, /**< Component has acquired previously unavailable dynamic resources */ - OMX_EventPortFormatDetected, /**< Component has detected a supported format. */ - OMX_EventKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ - OMX_EventVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ - OMX_EventMax = 0x7FFFFFFF + OMX_EventComponentResumed, /**< Component resumed due to reacquisition of resources */ + OMX_EventDynamicResourcesAvailable, /**< Component has acquired previously unavailable dynamic resources */ + OMX_EventPortFormatDetected, /**< Component has detected a supported format. */ + OMX_EventKhronosExtensions = 0x6F000000, /**< Reserved region for introducing Khronos Standard Extensions */ + OMX_EventVendorStartUnused = 0x7F000000, /**< Reserved region for introducing Vendor Extensions */ + + /** Event when tunneled decoder has rendered an output + * nData1 must contain the lower 32-bits of the buffer timestamp + * nData2 must contain the upper 32-bits of the buffer timestamp + */ + OMX_EventOutputRendered = 0x7F000001, + OMX_EventMax = 0x7FFFFFFF } OMX_EVENTTYPE; typedef struct OMX_CALLBACKTYPE diff --git a/include/media/openmax/OMX_IVCommon.h b/include/media/openmax/OMX_IVCommon.h index a5b9d18..f9b6f4b 100644 --- a/include/media/openmax/OMX_IVCommon.h +++ b/include/media/openmax/OMX_IVCommon.h @@ -157,6 +157,7 @@ typedef enum OMX_COLOR_FORMATTYPE { * an acceptable range once that is done. * */ OMX_COLOR_FormatAndroidOpaque = 0x7F000789, + OMX_COLOR_Format32BitRGBA8888 = 0x7F00A000, /** Flexible 8-bit YUV format. Codec should report this format * as being supported if it supports any YUV420 packed planar * or semiplanar formats. When port is set to use this format, diff --git a/include/media/openmax/OMX_IndexExt.h b/include/media/openmax/OMX_IndexExt.h index ea3d0da..51bba31 100644 --- a/include/media/openmax/OMX_IndexExt.h +++ b/include/media/openmax/OMX_IndexExt.h @@ -83,6 +83,8 @@ typedef enum OMX_INDEXEXTTYPE { /* Other configurations */ OMX_IndexExtOtherStartUnused = OMX_IndexKhronosExtensions + 0x00800000, OMX_IndexConfigAutoFramerateConversion, /**< reference: OMX_CONFIG_BOOLEANTYPE */ + OMX_IndexConfigPriority, /**< reference: OMX_PARAM_U32TYPE */ + OMX_IndexConfigOperatingRate, /**< reference: OMX_PARAM_U32TYPE in Q16 format for video and in Hz for audio */ /* Time configurations */ OMX_IndexExtTimeStartUnused = OMX_IndexKhronosExtensions + 0x00900000, diff --git a/libs/binder/Android.mk b/libs/binder/Android.mk index 79decfe..d5860ef 100644 --- a/libs/binder/Android.mk +++ b/libs/binder/Android.mk @@ -26,6 +26,8 @@ sources := \ IMemory.cpp \ IPCThreadState.cpp \ IPermissionController.cpp \ + IProcessInfoService.cpp \ + ProcessInfoService.cpp \ IServiceManager.cpp \ MemoryDealer.cpp \ MemoryBase.cpp \ diff --git a/libs/binder/IInterface.cpp b/libs/binder/IInterface.cpp index 8c60dc4..2fcd3d9 100644 --- a/libs/binder/IInterface.cpp +++ b/libs/binder/IInterface.cpp @@ -14,6 +14,8 @@ * limitations under the License. */ +#define LOG_TAG "IInterface" +#include <utils/Log.h> #include <binder/IInterface.h> namespace android { @@ -41,6 +43,25 @@ sp<IBinder> IInterface::asBinder(const sp<IInterface>& iface) return iface->onAsBinder(); } + // --------------------------------------------------------------------------- }; // namespace android + +extern "C" { + +void _ZN7android10IInterface8asBinderEv(void *retval, void* self) { + ALOGW("deprecated asBinder call, please update your code"); + //ALOGI("self: %p, retval: %p", self, retval); + android::sp<android::IBinder> *ret = new(retval) android::sp<android::IBinder>; + *ret = android::IInterface::asBinder((android::IInterface*)self); +} + +void _ZNK7android10IInterface8asBinderEv(void *retval, void *self) { + ALOGW("deprecated asBinder call, please update your code"); + //ALOGI("self: %p, retval: %p", self, retval); + android::sp<android::IBinder> *ret = new(retval) android::sp<android::IBinder>; + *ret = android::IInterface::asBinder((android::IInterface*)self); +} + +} // extern "C" diff --git a/libs/binder/IPCThreadState.cpp b/libs/binder/IPCThreadState.cpp index 9f68aa8..ef88181 100644 --- a/libs/binder/IPCThreadState.cpp +++ b/libs/binder/IPCThreadState.cpp @@ -399,6 +399,18 @@ void IPCThreadState::flushCommands() talkWithDriver(false); } +void IPCThreadState::blockUntilThreadAvailable() +{ + pthread_mutex_lock(&mProcess->mThreadCountLock); + while (mProcess->mExecutingThreadsCount >= mProcess->mMaxThreads) { + ALOGW("Waiting for thread to be free. mExecutingThreadsCount=%lu mMaxThreads=%lu\n", + static_cast<unsigned long>(mProcess->mExecutingThreadsCount), + static_cast<unsigned long>(mProcess->mMaxThreads)); + pthread_cond_wait(&mProcess->mThreadCountDecrement, &mProcess->mThreadCountLock); + } + pthread_mutex_unlock(&mProcess->mThreadCountLock); +} + status_t IPCThreadState::getAndExecuteCommand() { status_t result; @@ -414,8 +426,17 @@ status_t IPCThreadState::getAndExecuteCommand() << getReturnString(cmd) << endl; } + pthread_mutex_lock(&mProcess->mThreadCountLock); + mProcess->mExecutingThreadsCount++; + pthread_mutex_unlock(&mProcess->mThreadCountLock); + result = executeCommand(cmd); + pthread_mutex_lock(&mProcess->mThreadCountLock); + mProcess->mExecutingThreadsCount--; + pthread_cond_broadcast(&mProcess->mThreadCountDecrement); + pthread_mutex_unlock(&mProcess->mThreadCountLock); + // After executing the command, ensure that the thread is returned to the // foreground cgroup before rejoining the pool. The driver takes care of // restoring the priority, but doesn't do anything with cgroups so we diff --git a/libs/binder/IProcessInfoService.cpp b/libs/binder/IProcessInfoService.cpp new file mode 100644 index 0000000..d86eb27 --- /dev/null +++ b/libs/binder/IProcessInfoService.cpp @@ -0,0 +1,94 @@ +/* + * Copyright 2015 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. + */ + +#include <binder/IProcessInfoService.h> +#include <binder/Parcel.h> +#include <utils/Errors.h> +#include <sys/types.h> + +namespace android { + +// ---------------------------------------------------------------------- + +class BpProcessInfoService : public BpInterface<IProcessInfoService> { +public: + BpProcessInfoService(const sp<IBinder>& impl) + : BpInterface<IProcessInfoService>(impl) {} + + virtual status_t getProcessStatesFromPids(size_t length, /*in*/ int32_t* pids, + /*out*/ int32_t* states) + { + Parcel data, reply; + data.writeInterfaceToken(IProcessInfoService::getInterfaceDescriptor()); + data.writeInt32Array(length, pids); + data.writeInt32(length); // write length of output array, used by java AIDL stubs + status_t err = remote()->transact(GET_PROCESS_STATES_FROM_PIDS, data, &reply); + if (err != NO_ERROR || ((err = reply.readExceptionCode()) != NO_ERROR)) { + return err; + } + int32_t replyLen = reply.readInt32(); + if (static_cast<size_t>(replyLen) != length) { + return NOT_ENOUGH_DATA; + } + if (replyLen > 0 && (err = reply.read(states, length * sizeof(*states))) != NO_ERROR) { + return err; + } + return reply.readInt32(); + } + +}; + +IMPLEMENT_META_INTERFACE(ProcessInfoService, "android.os.IProcessInfoService"); + +// ---------------------------------------------------------------------- + +status_t BnProcessInfoService::onTransact( uint32_t code, const Parcel& data, Parcel* reply, + uint32_t flags) { + switch(code) { + case GET_PROCESS_STATES_FROM_PIDS: { + CHECK_INTERFACE(IProcessInfoService, data, reply); + int32_t arrayLen = data.readInt32(); + if (arrayLen <= 0) { + reply->writeNoException(); + reply->writeInt32(0); + reply->writeInt32(NOT_ENOUGH_DATA); + return NO_ERROR; + } + + size_t len = static_cast<size_t>(arrayLen); + int32_t pids[len]; + status_t res = data.read(pids, len * sizeof(*pids)); + + // Ignore output array length returned in the parcel here, as the states array must + // always be the same length as the input PIDs array. + int32_t states[len]; + for (size_t i = 0; i < len; i++) states[i] = -1; + if (res == NO_ERROR) { + res = getProcessStatesFromPids(len, /*in*/ pids, /*out*/ states); + } + reply->writeNoException(); + reply->writeInt32Array(len, states); + reply->writeInt32(res); + return NO_ERROR; + } break; + default: + return BBinder::onTransact(code, data, reply, flags); + } +} + +// ---------------------------------------------------------------------- + +}; // namespace android diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp index 2c566f9..0e11d53 100644 --- a/libs/binder/Parcel.cpp +++ b/libs/binder/Parcel.cpp @@ -54,7 +54,17 @@ // --------------------------------------------------------------------------- -#define PAD_SIZE(s) (((s)+3)&~3) +// This macro should never be used at runtime, as a too large value +// of s could cause an integer overflow. Instead, you should always +// use the wrapper function pad_size() +#define PAD_SIZE_UNSAFE(s) (((s)+3)&~3) + +static size_t pad_size(size_t s) { + if (s > (SIZE_T_MAX - 3)) { + abort(); + } + return PAD_SIZE_UNSAFE(s); +} // Note: must be kept in sync with android/os/StrictMode.java's PENALTY_GATHER #define STRICT_MODE_PENALTY_GATHER (0x40 << 16) @@ -355,6 +365,12 @@ size_t Parcel::dataCapacity() const status_t Parcel::setDataSize(size_t size) { + if (size > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + status_t err; err = continueWrite(size); if (err == NO_ERROR) { @@ -366,18 +382,36 @@ status_t Parcel::setDataSize(size_t size) void Parcel::setDataPosition(size_t pos) const { + if (pos > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + abort(); + } + mDataPos = pos; mNextObjectHint = 0; } status_t Parcel::setDataCapacity(size_t size) { + if (size > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + if (size > mDataCapacity) return continueWrite(size); return NO_ERROR; } status_t Parcel::setData(const uint8_t* buffer, size_t len) { + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + status_t err = restartWrite(len); if (err == NO_ERROR) { memcpy(const_cast<uint8_t*>(data()), buffer, len); @@ -401,6 +435,12 @@ status_t Parcel::appendFrom(const Parcel *parcel, size_t offset, size_t len) return NO_ERROR; } + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + // range checks against the source parcel size if ((offset > parcel->mDataSize) || (len > parcel->mDataSize) @@ -561,6 +601,12 @@ void Parcel::setError(status_t err) status_t Parcel::finishWrite(size_t len) { + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + //printf("Finish write of %d\n", len); mDataPos += len; ALOGV("finishWrite Setting data pos of %p to %zu", this, mDataPos); @@ -574,6 +620,12 @@ status_t Parcel::finishWrite(size_t len) status_t Parcel::writeUnpadded(const void* data, size_t len) { + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + size_t end = mDataPos + len; if (end < mDataPos) { // integer overflow @@ -593,6 +645,12 @@ restart_write: status_t Parcel::write(const void* data, size_t len) { + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + void* const d = writeInplace(len); if (d) { memcpy(d, data, len); @@ -603,7 +661,13 @@ status_t Parcel::write(const void* data, size_t len) void* Parcel::writeInplace(size_t len) { - const size_t padded = PAD_SIZE(len); + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return NULL; + } + + const size_t padded = pad_size(len); // sanity check for integer overflow if (mDataPos+padded < mDataPos) { @@ -652,6 +716,12 @@ status_t Parcel::writeUint32(uint32_t val) } status_t Parcel::writeInt32Array(size_t len, const int32_t *val) { + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + if (!val) { return writeAligned(-1); } @@ -662,6 +732,12 @@ status_t Parcel::writeInt32Array(size_t len, const int32_t *val) { return ret; } status_t Parcel::writeByteArray(size_t len, const uint8_t *val) { + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + if (!val) { return writeAligned(-1); } @@ -677,6 +753,11 @@ status_t Parcel::writeInt64(int64_t val) return writeAligned(val); } +status_t Parcel::writeUint64(uint64_t val) +{ + return writeAligned(val); +} + status_t Parcel::writePointer(uintptr_t val) { return writeAligned<binder_uintptr_t>(val); @@ -835,6 +916,12 @@ status_t Parcel::writeBlob(size_t len, WritableBlob* outBlob) { status_t status; + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + if (!mAllowFds || len <= IN_PLACE_BLOB_LIMIT) { ALOGV("writeBlob: write in place"); status = writeInt32(0); @@ -851,6 +938,8 @@ status_t Parcel::writeBlob(size_t len, WritableBlob* outBlob) int fd = ashmem_create_region("Parcel Blob", len); if (fd < 0) return NO_MEMORY; + mBlobAshmemSize += len; + int result = ashmem_set_prot_region(fd, PROT_READ | PROT_WRITE); if (result < 0) { status = result; @@ -887,6 +976,12 @@ status_t Parcel::write(const FlattenableHelperInterface& val) const size_t len = val.getFlattenedSize(); const size_t fd_count = val.getFdCount(); + if ((len > INT32_MAX) || (fd_count > INT32_MAX)) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + err = this->writeInt32(len); if (err) return err; @@ -894,7 +989,7 @@ status_t Parcel::write(const FlattenableHelperInterface& val) if (err) return err; // payload - void* const buf = this->writeInplace(PAD_SIZE(len)); + void* const buf = this->writeInplace(pad_size(len)); if (buf == NULL) return BAD_VALUE; @@ -968,10 +1063,16 @@ void Parcel::remove(size_t /*start*/, size_t /*amt*/) status_t Parcel::read(void* outData, size_t len) const { - if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize - && len <= PAD_SIZE(len)) { + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + + if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize + && len <= pad_size(len)) { memcpy(outData, mData+mDataPos, len); - mDataPos += PAD_SIZE(len); + mDataPos += pad_size(len); ALOGV("read Setting data pos of %p to %zu", this, mDataPos); return NO_ERROR; } @@ -980,10 +1081,16 @@ status_t Parcel::read(void* outData, size_t len) const const void* Parcel::readInplace(size_t len) const { - if ((mDataPos+PAD_SIZE(len)) >= mDataPos && (mDataPos+PAD_SIZE(len)) <= mDataSize - && len <= PAD_SIZE(len)) { + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return NULL; + } + + if ((mDataPos+pad_size(len)) >= mDataPos && (mDataPos+pad_size(len)) <= mDataSize + && len <= pad_size(len)) { const void* data = mData+mDataPos; - mDataPos += PAD_SIZE(len); + mDataPos += pad_size(len); ALOGV("readInplace Setting data pos of %p to %zu", this, mDataPos); return data; } @@ -992,7 +1099,7 @@ const void* Parcel::readInplace(size_t len) const template<class T> status_t Parcel::readAligned(T *pArg) const { - COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T)); + COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T)); if ((mDataPos+sizeof(T)) <= mDataSize) { const void* data = mData+mDataPos; @@ -1016,7 +1123,7 @@ T Parcel::readAligned() const { template<class T> status_t Parcel::writeAligned(T val) { - COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE(sizeof(T)) == sizeof(T)); + COMPILE_TIME_ASSERT_FUNCTION_SCOPE(PAD_SIZE_UNSAFE(sizeof(T)) == sizeof(T)); if ((mDataPos+sizeof(val)) <= mDataCapacity) { restart_write: @@ -1060,6 +1167,16 @@ int64_t Parcel::readInt64() const return readAligned<int64_t>(); } +status_t Parcel::readUint64(uint64_t *pArg) const +{ + return readAligned(pArg); +} + +uint64_t Parcel::readUint64() const +{ + return readAligned<uint64_t>(); +} + status_t Parcel::readPointer(uintptr_t *pArg) const { status_t ret; @@ -1147,7 +1264,7 @@ const char* Parcel::readCString() const const char* eos = reinterpret_cast<const char*>(memchr(str, 0, avail)); if (eos) { const size_t len = eos - str; - mDataPos += PAD_SIZE(len+1); + mDataPos += pad_size(len+1); ALOGV("readCString Setting data pos of %p to %zu", this, mDataPos); return str; } @@ -1306,8 +1423,14 @@ status_t Parcel::read(FlattenableHelperInterface& val) const const size_t len = this->readInt32(); const size_t fd_count = this->readInt32(); + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + // payload - void const* const buf = this->readInplace(PAD_SIZE(len)); + void const* const buf = this->readInplace(pad_size(len)); if (buf == NULL) return BAD_VALUE; @@ -1546,6 +1669,12 @@ void Parcel::freeDataNoInit() status_t Parcel::growData(size_t len) { + if (len > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + size_t newSize = ((mDataSize+len)*3)/2; return (newSize <= mDataSize) ? (status_t) NO_MEMORY @@ -1554,6 +1683,12 @@ status_t Parcel::growData(size_t len) status_t Parcel::restartWrite(size_t desired) { + if (desired > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + if (mOwner) { freeData(); return continueWrite(desired); @@ -1594,6 +1729,12 @@ status_t Parcel::restartWrite(size_t desired) status_t Parcel::continueWrite(size_t desired) { + if (desired > INT32_MAX) { + // don't accept size_t values which may have come from an + // inadvertent conversion from a negative int. + return BAD_VALUE; + } + // If shrinking, first adjust for any objects that appear // after the new data size. size_t objectsSize = mObjectsSize; @@ -1762,6 +1903,7 @@ void Parcel::initState() mFdsKnown = true; mAllowFds = true; mOwner = NULL; + mBlobAshmemSize = 0; } void Parcel::scanForFds() const @@ -1779,6 +1921,11 @@ void Parcel::scanForFds() const mFdsKnown = true; } +size_t Parcel::getBlobAshmemSize() const +{ + return mBlobAshmemSize; +} + // --- Parcel::Blob --- Parcel::Blob::Blob() : diff --git a/libs/binder/ProcessInfoService.cpp b/libs/binder/ProcessInfoService.cpp new file mode 100644 index 0000000..fb28643 --- /dev/null +++ b/libs/binder/ProcessInfoService.cpp @@ -0,0 +1,70 @@ +/* + * Copyright 2015 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. + */ + +#include <binder/ProcessInfoService.h> +#include <binder/IServiceManager.h> + +#include <utils/Log.h> +#include <utils/String16.h> + +namespace android { + +ProcessInfoService::ProcessInfoService() { + updateBinderLocked(); +} + +status_t ProcessInfoService::getProcessStatesImpl(size_t length, /*in*/ int32_t* pids, + /*out*/ int32_t* states) { + status_t err = NO_ERROR; + sp<IProcessInfoService> pis; + mProcessInfoLock.lock(); + pis = mProcessInfoService; + mProcessInfoLock.unlock(); + + for (int i = 0; i < BINDER_ATTEMPT_LIMIT; i++) { + + if (pis != NULL) { + err = pis->getProcessStatesFromPids(length, /*in*/ pids, /*out*/ states); + if (err == NO_ERROR) return NO_ERROR; // success + if (IInterface::asBinder(pis)->isBinderAlive()) return err; + } + sleep(1); + + mProcessInfoLock.lock(); + if (pis == mProcessInfoService) { + updateBinderLocked(); + } + pis = mProcessInfoService; + mProcessInfoLock.unlock(); + } + + ALOGW("%s: Could not retrieve process states from ProcessInfoService after %d retries.", + __FUNCTION__, BINDER_ATTEMPT_LIMIT); + + return TIMED_OUT; +} + +void ProcessInfoService::updateBinderLocked() { + const sp<IServiceManager> sm(defaultServiceManager()); + if (sm != NULL) { + const String16 name("processinfo"); + mProcessInfoService = interface_cast<IProcessInfoService>(sm->checkService(name)); + } +} + +ANDROID_SINGLETON_STATIC_INSTANCE(ProcessInfoService); + +}; // namespace android diff --git a/libs/binder/ProcessState.cpp b/libs/binder/ProcessState.cpp index 303d6cf..016d3c5 100644 --- a/libs/binder/ProcessState.cpp +++ b/libs/binder/ProcessState.cpp @@ -42,12 +42,13 @@ #include <sys/stat.h> #define BINDER_VM_SIZE ((1*1024*1024) - (4096 *2)) +#define DEFAULT_MAX_BINDER_THREADS 15 // --------------------------------------------------------------------------- namespace android { - + class PoolThread : public Thread { public: @@ -294,7 +295,9 @@ void ProcessState::spawnPooledThread(bool isMain) status_t ProcessState::setThreadPoolMaxThreadCount(size_t maxThreads) { status_t result = NO_ERROR; - if (ioctl(mDriverFD, BINDER_SET_MAX_THREADS, &maxThreads) == -1) { + if (ioctl(mDriverFD, BINDER_SET_MAX_THREADS, &maxThreads) != -1) { + mMaxThreads = maxThreads; + } else { result = -errno; ALOGE("Binder ioctl to set max threads failed: %s", strerror(-result)); } @@ -322,7 +325,7 @@ static int open_driver() close(fd); fd = -1; } - size_t maxThreads = 15; + size_t maxThreads = DEFAULT_MAX_BINDER_THREADS; result = ioctl(fd, BINDER_SET_MAX_THREADS, &maxThreads); if (result == -1) { ALOGE("Binder ioctl to set max threads failed: %s", strerror(errno)); @@ -336,6 +339,10 @@ static int open_driver() ProcessState::ProcessState() : mDriverFD(open_driver()) , mVMStart(MAP_FAILED) + , mThreadCountLock(PTHREAD_MUTEX_INITIALIZER) + , mThreadCountDecrement(PTHREAD_COND_INITIALIZER) + , mExecutingThreadsCount(0) + , mMaxThreads(DEFAULT_MAX_BINDER_THREADS) , mManagesContexts(false) , mBinderContextCheckFunc(NULL) , mBinderContextUserData(NULL) diff --git a/libs/gui/ISensorServer.cpp b/libs/gui/ISensorServer.cpp index 8e09e7c..140712e 100644 --- a/libs/gui/ISensorServer.cpp +++ b/libs/gui/ISensorServer.cpp @@ -35,6 +35,7 @@ namespace android { enum { GET_SENSOR_LIST = IBinder::FIRST_CALL_TRANSACTION, CREATE_SENSOR_EVENT_CONNECTION, + ENABLE_DATA_INJECTION }; class BpSensorServer : public BpInterface<ISensorServer> @@ -63,13 +64,24 @@ public: return v; } - virtual sp<ISensorEventConnection> createSensorEventConnection() + virtual sp<ISensorEventConnection> createSensorEventConnection(const String8& packageName, + int mode) { Parcel data, reply; data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor()); + data.writeString8(packageName); + data.writeInt32(mode); remote()->transact(CREATE_SENSOR_EVENT_CONNECTION, data, &reply); return interface_cast<ISensorEventConnection>(reply.readStrongBinder()); } + + virtual status_t enableDataInjection(int enable) { + Parcel data, reply; + data.writeInterfaceToken(ISensorServer::getInterfaceDescriptor()); + data.writeInt32(enable); + remote()->transact(ENABLE_DATA_INJECTION, data, &reply); + return reply.readInt32(); + } }; // Out-of-line virtual method definition to trigger vtable emission in this @@ -96,10 +108,19 @@ status_t BnSensorServer::onTransact( } case CREATE_SENSOR_EVENT_CONNECTION: { CHECK_INTERFACE(ISensorServer, data, reply); - sp<ISensorEventConnection> connection(createSensorEventConnection()); + String8 packageName = data.readString8(); + int32_t mode = data.readInt32(); + sp<ISensorEventConnection> connection(createSensorEventConnection(packageName, mode)); reply->writeStrongBinder(IInterface::asBinder(connection)); return NO_ERROR; } + case ENABLE_DATA_INJECTION: { + CHECK_INTERFACE(ISensorServer, data, reply); + int32_t enable = data.readInt32(); + status_t ret = enableDataInjection(enable); + reply->writeInt32(static_cast<int32_t>(ret)); + return NO_ERROR; + } } return BBinder::onTransact(code, data, reply, flags); } diff --git a/libs/gui/SensorEventQueue.cpp b/libs/gui/SensorEventQueue.cpp index 76ae470..8b2018f 100644 --- a/libs/gui/SensorEventQueue.cpp +++ b/libs/gui/SensorEventQueue.cpp @@ -149,6 +149,16 @@ status_t SensorEventQueue::setEventRate(Sensor const* sensor, nsecs_t ns) const return mSensorEventConnection->setEventRate(sensor->getHandle(), ns); } +status_t SensorEventQueue::injectSensorEvent(const ASensorEvent& event) { + // Blocking call. + ssize_t size = ::send(mSensorChannel->getFd(), &event, sizeof(event), MSG_NOSIGNAL); + if (size < 0) { + ALOGE("injectSensorEvent failure %zd %d", size, mSensorChannel->getFd()); + return INVALID_OPERATION; + } + return NO_ERROR; +} + void SensorEventQueue::sendAck(const ASensorEvent* events, int count) { for (int i = 0; i < count; ++i) { if (events[i].flags & WAKE_UP_SENSOR_EVENT_NEEDS_ACK) { diff --git a/libs/gui/SensorManager.cpp b/libs/gui/SensorManager.cpp index d6df404..cedcf56 100644 --- a/libs/gui/SensorManager.cpp +++ b/libs/gui/SensorManager.cpp @@ -100,8 +100,6 @@ status_t SensorManager::assertStateLocked() const { return NO_ERROR; } - - ssize_t SensorManager::getSensorList(Sensor const* const** list) const { Mutex::Autolock _l(mLock); @@ -139,18 +137,17 @@ Sensor const* SensorManager::getDefaultSensor(int type) return NULL; } -sp<SensorEventQueue> SensorManager::createEventQueue() -{ +sp<SensorEventQueue> SensorManager::createEventQueue(String8 packageName, int mode) { sp<SensorEventQueue> queue; Mutex::Autolock _l(mLock); while (assertStateLocked() == NO_ERROR) { sp<ISensorEventConnection> connection = - mSensorServer->createSensorEventConnection(); + mSensorServer->createSensorEventConnection(packageName, mode); if (connection == NULL) { - // SensorService just died. - ALOGE("createEventQueue: connection is NULL. SensorService died."); - continue; + // SensorService just died or the app doesn't have required permissions. + ALOGE("createEventQueue: connection is NULL."); + return NULL; } queue = new SensorEventQueue(connection); break; @@ -158,5 +155,13 @@ sp<SensorEventQueue> SensorManager::createEventQueue() return queue; } +status_t SensorManager::enableDataInjection(bool enable) { + Mutex::Autolock _l(mLock); + if (assertStateLocked() == NO_ERROR) { + return mSensorServer->enableDataInjection(enable); + } + return INVALID_OPERATION; +} + // ---------------------------------------------------------------------------- }; // namespace android diff --git a/libs/input/Android.mk b/libs/input/Android.mk index f1921a4..944ac7f 100644 --- a/libs/input/Android.mk +++ b/libs/input/Android.mk @@ -27,6 +27,7 @@ commonSources := \ deviceSources := \ $(commonSources) \ + IInputFlinger.cpp \ InputTransport.cpp \ VelocityControl.cpp \ VelocityTracker.cpp diff --git a/libs/input/IInputFlinger.cpp b/libs/input/IInputFlinger.cpp new file mode 100644 index 0000000..e009731 --- /dev/null +++ b/libs/input/IInputFlinger.cpp @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <stdint.h> +#include <sys/types.h> + +#include <binder/Parcel.h> +#include <binder/IPCThreadState.h> +#include <binder/IServiceManager.h> + +#include <input/IInputFlinger.h> + + +namespace android { + +class BpInputFlinger : public BpInterface<IInputFlinger> { +public: + BpInputFlinger(const sp<IBinder>& impl) : + BpInterface<IInputFlinger>(impl) { } + + virtual status_t doSomething() { + Parcel data, reply; + data.writeInterfaceToken(IInputFlinger::getInterfaceDescriptor()); + remote()->transact(BnInputFlinger::DO_SOMETHING_TRANSACTION, data, &reply); + return reply.readInt32(); + } +}; + +IMPLEMENT_META_INTERFACE(InputFlinger, "android.input.IInputFlinger"); + + +status_t BnInputFlinger::onTransact( + uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags) { + switch(code) { + case DO_SOMETHING_TRANSACTION: { + CHECK_INTERFACE(IInputFlinger, data, reply); + reply->writeInt32(0); + break; + } + default: + return BBinder::onTransact(code, data, reply, flags); + } + return NO_ERROR; +} + +}; diff --git a/libs/input/InputDevice.cpp b/libs/input/InputDevice.cpp index b11110a..d755ed3 100644 --- a/libs/input/InputDevice.cpp +++ b/libs/input/InputDevice.cpp @@ -127,28 +127,31 @@ String8 getInputDeviceConfigurationFilePathByName( // --- InputDeviceInfo --- InputDeviceInfo::InputDeviceInfo() { - initialize(-1, 0, -1, InputDeviceIdentifier(), String8(), false); + initialize(-1, 0, -1, InputDeviceIdentifier(), String8(), false, false); } InputDeviceInfo::InputDeviceInfo(const InputDeviceInfo& other) : mId(other.mId), mGeneration(other.mGeneration), mControllerNumber(other.mControllerNumber), mIdentifier(other.mIdentifier), mAlias(other.mAlias), mIsExternal(other.mIsExternal), - mSources(other.mSources), mKeyboardType(other.mKeyboardType), - mKeyCharacterMap(other.mKeyCharacterMap), mHasVibrator(other.mHasVibrator), - mHasButtonUnderPad(other.mHasButtonUnderPad), mMotionRanges(other.mMotionRanges) { + mHasMic(other.mHasMic), mSources(other.mSources), + mKeyboardType(other.mKeyboardType), mKeyCharacterMap(other.mKeyCharacterMap), + mHasVibrator(other.mHasVibrator), mHasButtonUnderPad(other.mHasButtonUnderPad), + mMotionRanges(other.mMotionRanges) { } InputDeviceInfo::~InputDeviceInfo() { } void InputDeviceInfo::initialize(int32_t id, int32_t generation, int32_t controllerNumber, - const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal) { + const InputDeviceIdentifier& identifier, const String8& alias, bool isExternal, + bool hasMic) { mId = id; mGeneration = generation; mControllerNumber = controllerNumber; mIdentifier = identifier; mAlias = alias; mIsExternal = isExternal; + mHasMic = hasMic; mSources = 0; mKeyboardType = AINPUT_KEYBOARD_TYPE_NONE; mHasVibrator = false; diff --git a/services/inputflinger/Android.mk b/services/inputflinger/Android.mk index 1af59a3..ed867d8 100644 --- a/services/inputflinger/Android.mk +++ b/services/inputflinger/Android.mk @@ -45,3 +45,5 @@ LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) LOCAL_MODULE := libinputflinger include $(BUILD_SHARED_LIBRARY) + +include $(call all-makefiles-under,$(LOCAL_PATH)) diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp index 93ce010..6b60c7c 100644 --- a/services/inputflinger/EventHub.cpp +++ b/services/inputflinger/EventHub.cpp @@ -131,6 +131,13 @@ uint32_t getAbsAxisUsage(int32_t axis, uint32_t deviceClasses) { } } + // External stylus gets the pressure axis + if (deviceClasses & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { + if (axis == ABS_PRESSURE) { + return INPUT_DEVICE_CLASS_EXTERNAL_STYLUS; + } + } + // Joystick devices get the rest. return deviceClasses & INPUT_DEVICE_CLASS_JOYSTICK; } @@ -1185,6 +1192,16 @@ status_t EventHub::openDeviceLocked(const char *devicePath) { && test_bit(ABS_X, device->absBitmask) && test_bit(ABS_Y, device->absBitmask)) { device->classes |= INPUT_DEVICE_CLASS_TOUCH; + // Is this a BT stylus? + } else if ((test_bit(ABS_PRESSURE, device->absBitmask) || + test_bit(BTN_TOUCH, device->keyBitmask)) + && !test_bit(ABS_X, device->absBitmask) + && !test_bit(ABS_Y, device->absBitmask)) { + device->classes |= INPUT_DEVICE_CLASS_EXTERNAL_STYLUS; + // Keyboard will try to claim some of the buttons but we really want to reserve those so we + // can fuse it with the touch screen data, so just take them back. Note this means an + // external stylus cannot also be a keyboard device. + device->classes &= ~INPUT_DEVICE_CLASS_KEYBOARD; } // See if this device is a joystick. @@ -1279,6 +1296,11 @@ status_t EventHub::openDeviceLocked(const char *devicePath) { return -1; } + // Determine whether the device has a mic. + if (deviceHasMicLocked(device)) { + device->classes |= INPUT_DEVICE_CLASS_MIC; + } + // Determine whether the device is external or internal. if (isExternalDeviceLocked(device)) { device->classes |= INPUT_DEVICE_CLASS_EXTERNAL; @@ -1293,7 +1315,10 @@ status_t EventHub::openDeviceLocked(const char *devicePath) { // Register with epoll. struct epoll_event eventItem; memset(&eventItem, 0, sizeof(eventItem)); - eventItem.events = mUsingEpollWakeup ? EPOLLIN : EPOLLIN | EPOLLWAKEUP; + eventItem.events = EPOLLIN; + if (mUsingEpollWakeup) { + eventItem.events |= EPOLLWAKEUP; + } eventItem.data.u32 = deviceId; if (epoll_ctl(mEpollFd, EPOLL_CTL_ADD, fd, &eventItem)) { ALOGE("Could not add device fd to epoll instance. errno=%d", errno); @@ -1412,6 +1437,16 @@ bool EventHub::isExternalDeviceLocked(Device* device) { return device->identifier.bus == BUS_USB || device->identifier.bus == BUS_BLUETOOTH; } +bool EventHub::deviceHasMicLocked(Device* device) { + if (device->configuration) { + bool value; + if (device->configuration->tryGetProperty(String8("audio.mic"), value)) { + return value; + } + } + return false; +} + int32_t EventHub::getNextControllerNumberLocked(Device* device) { if (mControllerNumbers.isFull()) { ALOGI("Maximum number of controllers reached, assigning controller number 0 to device %s", diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h index 20179ae..3ec4910 100644 --- a/services/inputflinger/EventHub.h +++ b/services/inputflinger/EventHub.h @@ -131,6 +131,12 @@ enum { /* The input device has a vibrator (supports FF_RUMBLE). */ INPUT_DEVICE_CLASS_VIBRATOR = 0x00000200, + /* The input device has a microphone. */ + INPUT_DEVICE_CLASS_MIC = 0x00000400, + + /* The input device is an external stylus (has data we want to fuse with touch data). */ + INPUT_DEVICE_CLASS_EXTERNAL_STYLUS = 0x00000800, + /* The input device is virtual (not a real device, not part of UI configuration). */ INPUT_DEVICE_CLASS_VIRTUAL = 0x40000000, @@ -394,6 +400,7 @@ private: status_t loadKeyMapLocked(Device* device); bool isExternalDeviceLocked(Device* device); + bool deviceHasMicLocked(Device* device); int32_t getNextControllerNumberLocked(Device* device); void releaseControllerNumberLocked(Device* device); diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp index 318c85f..f4c3928 100644 --- a/services/inputflinger/InputReader.cpp +++ b/services/inputflinger/InputReader.cpp @@ -39,12 +39,16 @@ // Log debug messages about the vibrator. #define DEBUG_VIBRATOR 0 +// Log debug messages about fusing stylus data. +#define DEBUG_STYLUS_FUSION 0 + #include "InputReader.h" #include <cutils/log.h> #include <input/Keyboard.h> #include <input/VirtualKeyMap.h> +#include <inttypes.h> #include <stddef.h> #include <stdlib.h> #include <unistd.h> @@ -65,6 +69,10 @@ namespace android { // Maximum number of slots supported when using the slot-based Multitouch Protocol B. static const size_t MAX_SLOTS = 32; +// Maximum amount of latency to add to touch events while waiting for data from an +// external stylus. +static const nsecs_t EXTERNAL_STYLUS_DATA_TIMEOUT = ms2ns(72); + // --- Static Functions --- template<typename T> @@ -381,6 +389,10 @@ void InputReader::addDeviceLocked(nsecs_t when, int32_t deviceId) { mDevices.add(deviceId, device); bumpGenerationLocked(); + + if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { + notifyExternalStylusPresenceChanged(); + } } void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) { @@ -403,6 +415,10 @@ void InputReader::removeDeviceLocked(nsecs_t when, int32_t deviceId) { device->getId(), device->getName().string(), device->getSources()); } + if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { + notifyExternalStylusPresenceChanged(); + } + device->reset(when); delete device; } @@ -417,6 +433,11 @@ InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controlle device->setExternal(true); } + // Devices with mics. + if (classes & INPUT_DEVICE_CLASS_MIC) { + device->setMic(true); + } + // Switch-like devices. if (classes & INPUT_DEVICE_CLASS_SWITCH) { device->addMapper(new SwitchInputMapper(device)); @@ -464,6 +485,11 @@ InputDevice* InputReader::createDeviceLocked(int32_t deviceId, int32_t controlle device->addMapper(new JoystickInputMapper(device)); } + // External stylus-like devices. + if (classes & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS) { + device->addMapper(new ExternalStylusInputMapper(device)); + } + return device; } @@ -534,6 +560,27 @@ int32_t InputReader::getGlobalMetaStateLocked() { return mGlobalMetaState; } +void InputReader::notifyExternalStylusPresenceChanged() { + refreshConfigurationLocked(InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE); +} + +void InputReader::getExternalStylusDevicesLocked(Vector<InputDeviceInfo>& outDevices) { + for (size_t i = 0; i < mDevices.size(); i++) { + InputDevice* device = mDevices.valueAt(i); + if (device->getClasses() & INPUT_DEVICE_CLASS_EXTERNAL_STYLUS && !device->isIgnored()) { + outDevices.push(); + device->getDeviceInfo(&outDevices.editTop()); + } + } +} + +void InputReader::dispatchExternalStylusState(const StylusState& state) { + for (size_t i = 0; i < mDevices.size(); i++) { + InputDevice* device = mDevices.valueAt(i); + device->updateExternalStylusState(state); + } +} + void InputReader::disableVirtualKeysUntilLocked(nsecs_t time) { mDisableVirtualKeysTimeout = time; } @@ -824,6 +871,15 @@ int32_t InputReader::ContextImpl::bumpGeneration() { return mReader->bumpGenerationLocked(); } +void InputReader::ContextImpl::getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices) { + // lock is already held by whatever called refreshConfigurationLocked + mReader->getExternalStylusDevicesLocked(outDevices); +} + +void InputReader::ContextImpl::dispatchExternalStylusState(const StylusState& state) { + mReader->dispatchExternalStylusState(state); +} + InputReaderPolicyInterface* InputReader::ContextImpl::getPolicy() { return mReader->mPolicy.get(); } @@ -858,7 +914,7 @@ InputDevice::InputDevice(InputReaderContext* context, int32_t id, int32_t genera int32_t controllerNumber, const InputDeviceIdentifier& identifier, uint32_t classes) : mContext(context), mId(id), mGeneration(generation), mControllerNumber(controllerNumber), mIdentifier(identifier), mClasses(classes), - mSources(0), mIsExternal(false), mDropUntilNextSync(false) { + mSources(0), mIsExternal(false), mHasMic(false), mDropUntilNextSync(false) { } InputDevice::~InputDevice() { @@ -877,6 +933,7 @@ void InputDevice::dump(String8& dump) { deviceInfo.getDisplayName().string()); dump.appendFormat(INDENT2 "Generation: %d\n", mGeneration); dump.appendFormat(INDENT2 "IsExternal: %s\n", toString(mIsExternal)); + dump.appendFormat(INDENT2 "HasMic: %s\n", toString(mHasMic)); dump.appendFormat(INDENT2 "Sources: 0x%08x\n", deviceInfo.getSources()); dump.appendFormat(INDENT2 "KeyboardType: %d\n", deviceInfo.getKeyboardType()); @@ -1006,10 +1063,17 @@ void InputDevice::timeoutExpired(nsecs_t when) { } } +void InputDevice::updateExternalStylusState(const StylusState& state) { + size_t numMappers = mMappers.size(); + for (size_t i = 0; i < numMappers; i++) { + InputMapper* mapper = mMappers[i]; + mapper->updateExternalStylusState(state); + } +} + void InputDevice::getDeviceInfo(InputDeviceInfo* outDeviceInfo) { outDeviceInfo->initialize(mId, mGeneration, mControllerNumber, mIdentifier, mAlias, - mIsExternal); - + mIsExternal, mHasMic); size_t numMappers = mMappers.size(); for (size_t i = 0; i < numMappers; i++) { InputMapper* mapper = mMappers[i]; @@ -1078,6 +1142,14 @@ void InputDevice::cancelVibrate(int32_t token) { } } +void InputDevice::cancelTouch(nsecs_t when) { + size_t numMappers = mMappers.size(); + for (size_t i = 0; i < numMappers; i++) { + InputMapper* mapper = mMappers[i]; + mapper->cancelTouch(when); + } +} + int32_t InputDevice::getMetaState() { int32_t result = 0; size_t numMappers = mMappers.size(); @@ -1277,7 +1349,9 @@ void TouchButtonAccumulator::configure(InputDevice* device) { void TouchButtonAccumulator::reset(InputDevice* device) { mBtnTouch = device->isKeyPressed(BTN_TOUCH); mBtnStylus = device->isKeyPressed(BTN_STYLUS); - mBtnStylus2 = device->isKeyPressed(BTN_STYLUS); + // BTN_0 is what gets mapped for the HID usage Digitizers.SecondaryBarrelSwitch + mBtnStylus2 = + device->isKeyPressed(BTN_STYLUS2) || device->isKeyPressed(BTN_0); mBtnToolFinger = device->isKeyPressed(BTN_TOOL_FINGER); mBtnToolPen = device->isKeyPressed(BTN_TOOL_PEN); mBtnToolRubber = device->isKeyPressed(BTN_TOOL_RUBBER); @@ -1318,6 +1392,7 @@ void TouchButtonAccumulator::process(const RawEvent* rawEvent) { mBtnStylus = rawEvent->value; break; case BTN_STYLUS2: + case BTN_0:// BTN_0 is what gets mapped for the HID usage Digitizers.SecondaryBarrelSwitch mBtnStylus2 = rawEvent->value; break; case BTN_TOOL_FINGER: @@ -1786,10 +1861,17 @@ void InputMapper::vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t re void InputMapper::cancelVibrate(int32_t token) { } +void InputMapper::cancelTouch(nsecs_t when) { +} + int32_t InputMapper::getMetaState() { return 0; } +void InputMapper::updateExternalStylusState(const StylusState& state) { + +} + void InputMapper::fadePointer() { } @@ -1811,6 +1893,12 @@ void InputMapper::dumpRawAbsoluteAxisInfo(String8& dump, } } +void InputMapper::dumpStylusState(String8& dump, const StylusState& state) { + dump.appendFormat(INDENT4 "When: %" PRId64 "\n", state.when); + dump.appendFormat(INDENT4 "Pressure: %f\n", state.pressure); + dump.appendFormat(INDENT4 "Button State: 0x%08x\n", state.buttons); + dump.appendFormat(INDENT4 "Tool Type: %" PRId32 "\n", state.toolType); +} // --- SwitchInputMapper --- @@ -2134,6 +2222,9 @@ void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode, getDevice(), keyCode, scanCode)) { return; } + if (policyFlags & POLICY_FLAG_GESTURE) { + mDevice->cancelTouch(when); + } mKeyDowns.push(); KeyDown& keyDown = mKeyDowns.editTop(); @@ -2689,12 +2780,12 @@ void TouchInputMapper::dump(String8& dump) { dump.appendFormat(INDENT4 "TiltYCenter: %0.3f\n", mTiltYCenter); dump.appendFormat(INDENT4 "TiltYScale: %0.3f\n", mTiltYScale); - dump.appendFormat(INDENT3 "Last Button State: 0x%08x\n", mLastButtonState); + dump.appendFormat(INDENT3 "Last Button State: 0x%08x\n", mLastRawState.buttonState); dump.appendFormat(INDENT3 "Last Raw Touch: pointerCount=%d\n", - mLastRawPointerData.pointerCount); - for (uint32_t i = 0; i < mLastRawPointerData.pointerCount; i++) { - const RawPointerData::Pointer& pointer = mLastRawPointerData.pointers[i]; + mLastRawState.rawPointerData.pointerCount); + for (uint32_t i = 0; i < mLastRawState.rawPointerData.pointerCount; i++) { + const RawPointerData::Pointer& pointer = mLastRawState.rawPointerData.pointers[i]; dump.appendFormat(INDENT4 "[%d]: id=%d, x=%d, y=%d, pressure=%d, " "touchMajor=%d, touchMinor=%d, toolMajor=%d, toolMinor=%d, " "orientation=%d, tiltX=%d, tiltY=%d, distance=%d, " @@ -2707,10 +2798,11 @@ void TouchInputMapper::dump(String8& dump) { } dump.appendFormat(INDENT3 "Last Cooked Touch: pointerCount=%d\n", - mLastCookedPointerData.pointerCount); - for (uint32_t i = 0; i < mLastCookedPointerData.pointerCount; i++) { - const PointerProperties& pointerProperties = mLastCookedPointerData.pointerProperties[i]; - const PointerCoords& pointerCoords = mLastCookedPointerData.pointerCoords[i]; + mLastCookedState.cookedPointerData.pointerCount); + for (uint32_t i = 0; i < mLastCookedState.cookedPointerData.pointerCount; i++) { + const PointerProperties& pointerProperties = + mLastCookedState.cookedPointerData.pointerProperties[i]; + const PointerCoords& pointerCoords = mLastCookedState.cookedPointerData.pointerCoords[i]; dump.appendFormat(INDENT4 "[%d]: id=%d, x=%0.3f, y=%0.3f, pressure=%0.3f, " "touchMajor=%0.3f, touchMinor=%0.3f, toolMajor=%0.3f, toolMinor=%0.3f, " "orientation=%0.3f, tilt=%0.3f, distance=%0.3f, " @@ -2727,9 +2819,18 @@ void TouchInputMapper::dump(String8& dump) { pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_TILT), pointerCoords.getAxisValue(AMOTION_EVENT_AXIS_DISTANCE), pointerProperties.toolType, - toString(mLastCookedPointerData.isHovering(i))); + toString(mLastCookedState.cookedPointerData.isHovering(i))); } + dump.append(INDENT3 "Stylus Fusion:\n"); + dump.appendFormat(INDENT4 "ExternalStylusConnected: %s\n", + toString(mExternalStylusConnected)); + dump.appendFormat(INDENT4 "External Stylus ID: %" PRId64 "\n", mExternalStylusId); + dump.appendFormat(INDENT4 "External Stylus Data Timeout: %" PRId64 "\n", + mExternalStylusDataTimeout); + dump.append(INDENT3 "External Stylus State:\n"); + dumpStylusState(dump, mExternalStylusState); + if (mDeviceMode == DEVICE_MODE_POINTER) { dump.appendFormat(INDENT3 "Pointer Gesture Detector:\n"); dump.appendFormat(INDENT4 "XMovementScale: %0.3f\n", @@ -2767,7 +2868,7 @@ void TouchInputMapper::configure(nsecs_t when, resolveCalibration(); } - if (!changes || (changes & InputReaderConfiguration::TOUCH_AFFINE_TRANSFORMATION)) { + if (!changes || (changes & InputReaderConfiguration::CHANGE_TOUCH_AFFINE_TRANSFORMATION)) { // Update location calibration to reflect current settings updateAffineTransformation(); } @@ -2782,7 +2883,8 @@ void TouchInputMapper::configure(nsecs_t when, bool resetNeeded = false; if (!changes || (changes & (InputReaderConfiguration::CHANGE_DISPLAY_INFO | InputReaderConfiguration::CHANGE_POINTER_GESTURE_ENABLEMENT - | InputReaderConfiguration::CHANGE_SHOW_TOUCHES))) { + | InputReaderConfiguration::CHANGE_SHOW_TOUCHES + | InputReaderConfiguration::CHANGE_EXTERNAL_STYLUS_PRESENCE))) { // Configure device sources, surface dimensions, orientation and // scaling factors. configureSurface(when, &resetNeeded); @@ -2795,6 +2897,16 @@ void TouchInputMapper::configure(nsecs_t when, } } +void TouchInputMapper::resolveExternalStylusPresence() { + Vector<InputDeviceInfo> devices; + mContext->getExternalStylusDevices(devices); + mExternalStylusConnected = !devices.isEmpty(); + + if (!mExternalStylusConnected) { + resetExternalStylus(); + } +} + void TouchInputMapper::configureParameters() { // Use the pointer presentation mode for devices that do not support distinct // multitouch. The spot-based presentation relies on being able to accurately @@ -2931,9 +3043,15 @@ void TouchInputMapper::dumpRawPointerAxes(String8& dump) { dumpRawAbsoluteAxisInfo(dump, mRawPointerAxes.slot, "Slot"); } +bool TouchInputMapper::hasExternalStylus() const { + return mExternalStylusConnected; +} + void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { int32_t oldDeviceMode = mDeviceMode; + resolveExternalStylusPresence(); + // Determine device mode. if (mParameters.deviceType == Parameters::DEVICE_TYPE_POINTER && mConfig.pointerGesturesEnabled) { @@ -2946,7 +3064,7 @@ void TouchInputMapper::configureSurface(nsecs_t when, bool* outResetNeeded) { && mParameters.hasAssociatedDisplay) { mSource = AINPUT_SOURCE_TOUCHSCREEN; mDeviceMode = DEVICE_MODE_DIRECT; - if (hasStylus()) { + if (hasStylus() || hasExternalStylus()) { mSource |= AINPUT_SOURCE_STYLUS; } } else if (mParameters.deviceType == Parameters::DEVICE_TYPE_TOUCH_NAVIGATION) { @@ -3691,28 +3809,21 @@ void TouchInputMapper::reset(nsecs_t when) { mWheelXVelocityControl.reset(); mWheelYVelocityControl.reset(); - mCurrentRawPointerData.clear(); - mLastRawPointerData.clear(); - mCurrentCookedPointerData.clear(); - mLastCookedPointerData.clear(); - mCurrentButtonState = 0; - mLastButtonState = 0; - mCurrentRawVScroll = 0; - mCurrentRawHScroll = 0; - mCurrentFingerIdBits.clear(); - mLastFingerIdBits.clear(); - mCurrentStylusIdBits.clear(); - mLastStylusIdBits.clear(); - mCurrentMouseIdBits.clear(); - mLastMouseIdBits.clear(); + mRawStatesPending.clear(); + mCurrentRawState.clear(); + mCurrentCookedState.clear(); + mLastRawState.clear(); + mLastCookedState.clear(); mPointerUsage = POINTER_USAGE_NONE; mSentHoverEnter = false; + mHavePointerIds = false; mDownTime = 0; mCurrentVirtualKey.down = false; mPointerGesture.reset(); mPointerSimple.reset(); + resetExternalStylus(); if (mPointerController != NULL) { mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); @@ -3722,6 +3833,13 @@ void TouchInputMapper::reset(nsecs_t when) { InputMapper::reset(when); } +void TouchInputMapper::resetExternalStylus() { + mExternalStylusState.clear(); + mExternalStylusId = -1; + mExternalStylusDataTimeout = LLONG_MAX; + mExternalStylusDataPending = false; +} + void TouchInputMapper::process(const RawEvent* rawEvent) { mCursorButtonAccumulator.process(rawEvent); mCursorScrollAccumulator.process(rawEvent); @@ -3733,155 +3851,264 @@ void TouchInputMapper::process(const RawEvent* rawEvent) { } void TouchInputMapper::sync(nsecs_t when) { + const RawState* last = mRawStatesPending.isEmpty() ? + &mCurrentRawState : &mRawStatesPending.top(); + + // Push a new state. + mRawStatesPending.push(); + RawState* next = &mRawStatesPending.editTop(); + next->clear(); + next->when = when; + // Sync button state. - mCurrentButtonState = mTouchButtonAccumulator.getButtonState() + next->buttonState = mTouchButtonAccumulator.getButtonState() | mCursorButtonAccumulator.getButtonState(); - // Sync scroll state. - mCurrentRawVScroll = mCursorScrollAccumulator.getRelativeVWheel(); - mCurrentRawHScroll = mCursorScrollAccumulator.getRelativeHWheel(); + // Sync scroll + next->rawVScroll = mCursorScrollAccumulator.getRelativeVWheel(); + next->rawHScroll = mCursorScrollAccumulator.getRelativeHWheel(); mCursorScrollAccumulator.finishSync(); - // Sync touch state. - bool havePointerIds = true; - mCurrentRawPointerData.clear(); - syncTouch(when, &havePointerIds); + // Sync touch + syncTouch(when, next); -#if DEBUG_RAW_EVENTS - if (!havePointerIds) { - ALOGD("syncTouch: pointerCount %d -> %d, no pointer ids", - mLastRawPointerData.pointerCount, - mCurrentRawPointerData.pointerCount); - } else { - ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, " - "hovering ids 0x%08x -> 0x%08x", - mLastRawPointerData.pointerCount, - mCurrentRawPointerData.pointerCount, - mLastRawPointerData.touchingIdBits.value, - mCurrentRawPointerData.touchingIdBits.value, - mLastRawPointerData.hoveringIdBits.value, - mCurrentRawPointerData.hoveringIdBits.value); + // Assign pointer ids. + if (!mHavePointerIds) { + assignPointerIds(last, next); } + +#if DEBUG_RAW_EVENTS + ALOGD("syncTouch: pointerCount %d -> %d, touching ids 0x%08x -> 0x%08x, " + "hovering ids 0x%08x -> 0x%08x", + last->rawPointerData.pointerCount, + next->rawPointerData.pointerCount, + last->rawPointerData.touchingIdBits.value, + next->rawPointerData.touchingIdBits.value, + last->rawPointerData.hoveringIdBits.value, + next->rawPointerData.hoveringIdBits.value); #endif - // Reset state that we will compute below. - mCurrentFingerIdBits.clear(); - mCurrentStylusIdBits.clear(); - mCurrentMouseIdBits.clear(); - mCurrentCookedPointerData.clear(); + processRawTouches(false /*timeout*/); +} +void TouchInputMapper::processRawTouches(bool timeout) { if (mDeviceMode == DEVICE_MODE_DISABLED) { // Drop all input if the device is disabled. - mCurrentRawPointerData.clear(); - mCurrentButtonState = 0; - } else { - // Preprocess pointer data. - if (!havePointerIds) { - assignPointerIds(); - } - - // Handle policy on initial down or hover events. - uint32_t policyFlags = 0; - bool initialDown = mLastRawPointerData.pointerCount == 0 - && mCurrentRawPointerData.pointerCount != 0; - bool buttonsPressed = mCurrentButtonState & ~mLastButtonState; - if (initialDown || buttonsPressed) { - // If this is a touch screen, hide the pointer on an initial down. - if (mDeviceMode == DEVICE_MODE_DIRECT) { - getContext()->fadePointer(); - } + mCurrentRawState.clear(); + mRawStatesPending.clear(); + return; + } - if (mParameters.wake) { - policyFlags |= POLICY_FLAG_WAKE; - } + // Drain any pending touch states. The invariant here is that the mCurrentRawState is always + // valid and must go through the full cook and dispatch cycle. This ensures that anything + // touching the current state will only observe the events that have been dispatched to the + // rest of the pipeline. + const size_t N = mRawStatesPending.size(); + size_t count; + for(count = 0; count < N; count++) { + const RawState& next = mRawStatesPending[count]; + + // A failure to assign the stylus id means that we're waiting on stylus data + // and so should defer the rest of the pipeline. + if (assignExternalStylusId(next, timeout)) { + break; } - // Synthesize key down from raw buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource, - policyFlags, mLastButtonState, mCurrentButtonState); + // All ready to go. + mExternalStylusDataPending = false; + mCurrentRawState.copyFrom(next); + cookAndDispatch(mCurrentRawState.when); + } + if (count != 0) { + mRawStatesPending.removeItemsAt(0, count); + } + + // TODO: If we still have pending stylus data that hasn't been mapped to a touch yet + // then set a timeout to synthesize a new touch event with the new data. Otherwise + // we will lose button and pressure information while the touch is stationary. + if (mExternalStylusDataPending) { + ALOGD("STYLUS TODO: Wiggle wiggle wiggle."); + } +} + +void TouchInputMapper::cookAndDispatch(nsecs_t when) { + // Always start with a clean state. + mCurrentCookedState.clear(); + + // Apply stylus buttons to current raw state. + applyExternalStylusButtonState(when); + + // Handle policy on initial down or hover events. + bool initialDown = mLastRawState.rawPointerData.pointerCount == 0 + && mCurrentRawState.rawPointerData.pointerCount != 0; - // Consume raw off-screen touches before cooking pointer data. - // If touches are consumed, subsequent code will not receive any pointer data. - if (consumeRawTouches(when, policyFlags)) { - mCurrentRawPointerData.clear(); + uint32_t policyFlags = 0; + bool buttonsPressed = mCurrentRawState.buttonState & ~mLastRawState.buttonState; + if (initialDown || buttonsPressed) { + // If this is a touch screen, hide the pointer on an initial down. + if (mDeviceMode == DEVICE_MODE_DIRECT) { + getContext()->fadePointer(); } - // Cook pointer data. This call populates the mCurrentCookedPointerData structure - // with cooked pointer data that has the same ids and indices as the raw data. - // The following code can use either the raw or cooked data, as needed. - cookPointerData(); + if (mParameters.wake) { + policyFlags |= POLICY_FLAG_WAKE; + } + } - // Dispatch the touches either directly or by translation through a pointer on screen. - if (mDeviceMode == DEVICE_MODE_POINTER) { - for (BitSet32 idBits(mCurrentRawPointerData.touchingIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); - if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS - || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { - mCurrentStylusIdBits.markBit(id); - } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER - || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { - mCurrentFingerIdBits.markBit(id); - } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) { - mCurrentMouseIdBits.markBit(id); - } + // Consume raw off-screen touches before cooking pointer data. + // If touches are consumed, subsequent code will not receive any pointer data. + if (consumeRawTouches(when, policyFlags)) { + mCurrentRawState.rawPointerData.clear(); + } + + // Cook pointer data. This call populates the mCurrentCookedState.cookedPointerData structure + // with cooked pointer data that has the same ids and indices as the raw data. + // The following code can use either the raw or cooked data, as needed. + cookPointerData(); + + // Apply stylus pressure to current cooked state. + applyExternalStylusTouchState(when); + + // Synthesize key down from raw buttons if needed. + synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_DOWN, when, getDeviceId(), mSource, + policyFlags, mLastRawState.buttonState, mCurrentRawState.buttonState); + + // Dispatch the touches either directly or by translation through a pointer on screen. + if (mDeviceMode == DEVICE_MODE_POINTER) { + for (BitSet32 idBits(mCurrentRawState.rawPointerData.touchingIdBits); + !idBits.isEmpty(); ) { + uint32_t id = idBits.clearFirstMarkedBit(); + const RawPointerData::Pointer& pointer = + mCurrentRawState.rawPointerData.pointerForId(id); + if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS + || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { + mCurrentCookedState.stylusIdBits.markBit(id); + } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_FINGER + || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { + mCurrentCookedState.fingerIdBits.markBit(id); + } else if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_MOUSE) { + mCurrentCookedState.mouseIdBits.markBit(id); } - for (BitSet32 idBits(mCurrentRawPointerData.hoveringIdBits); !idBits.isEmpty(); ) { - uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); - if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS - || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { - mCurrentStylusIdBits.markBit(id); - } + } + for (BitSet32 idBits(mCurrentRawState.rawPointerData.hoveringIdBits); + !idBits.isEmpty(); ) { + uint32_t id = idBits.clearFirstMarkedBit(); + const RawPointerData::Pointer& pointer = + mCurrentRawState.rawPointerData.pointerForId(id); + if (pointer.toolType == AMOTION_EVENT_TOOL_TYPE_STYLUS + || pointer.toolType == AMOTION_EVENT_TOOL_TYPE_ERASER) { + mCurrentCookedState.stylusIdBits.markBit(id); } + } - // Stylus takes precedence over all tools, then mouse, then finger. - PointerUsage pointerUsage = mPointerUsage; - if (!mCurrentStylusIdBits.isEmpty()) { - mCurrentMouseIdBits.clear(); - mCurrentFingerIdBits.clear(); - pointerUsage = POINTER_USAGE_STYLUS; - } else if (!mCurrentMouseIdBits.isEmpty()) { - mCurrentFingerIdBits.clear(); - pointerUsage = POINTER_USAGE_MOUSE; - } else if (!mCurrentFingerIdBits.isEmpty() || isPointerDown(mCurrentButtonState)) { - pointerUsage = POINTER_USAGE_GESTURES; - } + // Stylus takes precedence over all tools, then mouse, then finger. + PointerUsage pointerUsage = mPointerUsage; + if (!mCurrentCookedState.stylusIdBits.isEmpty()) { + mCurrentCookedState.mouseIdBits.clear(); + mCurrentCookedState.fingerIdBits.clear(); + pointerUsage = POINTER_USAGE_STYLUS; + } else if (!mCurrentCookedState.mouseIdBits.isEmpty()) { + mCurrentCookedState.fingerIdBits.clear(); + pointerUsage = POINTER_USAGE_MOUSE; + } else if (!mCurrentCookedState.fingerIdBits.isEmpty() || + isPointerDown(mCurrentRawState.buttonState)) { + pointerUsage = POINTER_USAGE_GESTURES; + } - dispatchPointerUsage(when, policyFlags, pointerUsage); - } else { - if (mDeviceMode == DEVICE_MODE_DIRECT - && mConfig.showTouches && mPointerController != NULL) { - mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT); - mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - - mPointerController->setButtonState(mCurrentButtonState); - mPointerController->setSpots(mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - mCurrentCookedPointerData.touchingIdBits); - } + dispatchPointerUsage(when, policyFlags, pointerUsage); + } else { + if (mDeviceMode == DEVICE_MODE_DIRECT + && mConfig.showTouches && mPointerController != NULL) { + mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT); + mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); - dispatchHoverExit(when, policyFlags); - dispatchTouches(when, policyFlags); - dispatchHoverEnterAndMove(when, policyFlags); + mPointerController->setButtonState(mCurrentRawState.buttonState); + mPointerController->setSpots(mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.touchingIdBits); } - // Synthesize key up from raw buttons if needed. - synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, - policyFlags, mLastButtonState, mCurrentButtonState); + dispatchHoverExit(when, policyFlags); + dispatchTouches(when, policyFlags); + dispatchHoverEnterAndMove(when, policyFlags); } - // Copy current touch to last touch in preparation for the next cycle. - mLastRawPointerData.copyFrom(mCurrentRawPointerData); - mLastCookedPointerData.copyFrom(mCurrentCookedPointerData); - mLastButtonState = mCurrentButtonState; - mLastFingerIdBits = mCurrentFingerIdBits; - mLastStylusIdBits = mCurrentStylusIdBits; - mLastMouseIdBits = mCurrentMouseIdBits; + // Synthesize key up from raw buttons if needed. + synthesizeButtonKeys(getContext(), AKEY_EVENT_ACTION_UP, when, getDeviceId(), mSource, + policyFlags, mLastRawState.buttonState, mCurrentRawState.buttonState); // Clear some transient state. - mCurrentRawVScroll = 0; - mCurrentRawHScroll = 0; + mCurrentRawState.rawVScroll = 0; + mCurrentRawState.rawHScroll = 0; + + // Copy current touch to last touch in preparation for the next cycle. + mLastRawState.copyFrom(mCurrentRawState); + mLastCookedState.copyFrom(mCurrentCookedState); +} + +void TouchInputMapper::applyExternalStylusButtonState(nsecs_t when) { + if (mDeviceMode == DEVICE_MODE_DIRECT && hasExternalStylus()) { + mCurrentRawState.buttonState |= mExternalStylusState.buttons; + } +} + +void TouchInputMapper::applyExternalStylusTouchState(nsecs_t when) { + CookedPointerData& cpd = mCurrentCookedState.cookedPointerData; + if (mExternalStylusId != -1 && cpd.isTouching(mExternalStylusId)) { + if (mExternalStylusState.pressure != 0.0f) { + PointerCoords& coords = cpd.editPointerCoordsWithId(mExternalStylusId); + coords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, mExternalStylusState.pressure); + } + + PointerProperties& properties = cpd.editPointerPropertiesWithId(mExternalStylusId); + if (mExternalStylusState.toolType != AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { + properties.toolType = mExternalStylusState.toolType; + } + } +} + +bool TouchInputMapper::assignExternalStylusId(const RawState& state, bool timeout) { + if (mDeviceMode != DEVICE_MODE_DIRECT || !hasExternalStylus()) { + return false; + } + + const bool initialDown = mLastRawState.rawPointerData.pointerCount == 0 + && state.rawPointerData.pointerCount != 0; + if (initialDown) { + if (mExternalStylusState.pressure != 0.0f) { +#if DEBUG_STYLUS_FUSION + ALOGD("Have both stylus and touch data, beginning fusion"); +#endif + mExternalStylusId = state.rawPointerData.touchingIdBits.firstMarkedBit(); + } else if (timeout) { +#if DEBUG_STYLUS_FUSION + ALOGD("Timeout expired, assuming touch is not a stylus."); +#endif + resetExternalStylus(); + } else { + nsecs_t now = systemTime(SYSTEM_TIME_MONOTONIC); + if (mExternalStylusDataTimeout == LLONG_MAX) { + mExternalStylusDataTimeout = now + EXTERNAL_STYLUS_DATA_TIMEOUT; + } +#if DEBUG_STYLUS_FUSION + ALOGD("No stylus data but stylus is connected, requesting timeout " + "(%" PRId64 "ms)", mExternalStylusDataTimeout); +#endif + getContext()->requestTimeoutAtTime(mExternalStylusDataTimeout); + return true; + } + } + + // Check if the stylus pointer has gone up. + if (mExternalStylusId != -1 && + !state.rawPointerData.touchingIdBits.hasBit(mExternalStylusId)) { +#if DEBUG_STYLUS_FUSION + ALOGD("Stylus pointer is going up"); +#endif + mExternalStylusId = -1; + } + + return false; } void TouchInputMapper::timeoutExpired(nsecs_t when) { @@ -3889,13 +4116,32 @@ void TouchInputMapper::timeoutExpired(nsecs_t when) { if (mPointerUsage == POINTER_USAGE_GESTURES) { dispatchPointerGestures(when, 0 /*policyFlags*/, true /*isTimeout*/); } + } else if (mDeviceMode == DEVICE_MODE_DIRECT) { + if (mExternalStylusDataTimeout < when) { + mExternalStylusDataTimeout = LLONG_MAX; + processRawTouches(true /*timeout*/); + } else if (mExternalStylusDataTimeout != LLONG_MAX) { + getContext()->requestTimeoutAtTime(mExternalStylusDataTimeout); + } + } +} + +void TouchInputMapper::updateExternalStylusState(const StylusState& state) { + mExternalStylusState.copyFrom(state); + if (mExternalStylusId != -1 || mExternalStylusDataTimeout != LLONG_MAX) { + // We're either in the middle of a fused stream of data or we're waiting on data before + // dispatching the initial down, so go ahead and dispatch now that we have fresh stylus + // data. + mExternalStylusDataTimeout = LLONG_MAX; + mExternalStylusDataPending = true; + processRawTouches(false /*timeout*/); } } bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) { // Check for release of a virtual key. if (mCurrentVirtualKey.down) { - if (mCurrentRawPointerData.touchingIdBits.isEmpty()) { + if (mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) { // Pointer went up while virtual key was down. mCurrentVirtualKey.down = false; if (!mCurrentVirtualKey.ignored) { @@ -3910,9 +4156,10 @@ bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) { return true; } - if (mCurrentRawPointerData.touchingIdBits.count() == 1) { - uint32_t id = mCurrentRawPointerData.touchingIdBits.firstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); + if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) { + uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit(); + const RawPointerData::Pointer& pointer = + mCurrentRawState.rawPointerData.pointerForId(id); const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y); if (virtualKey && virtualKey->keyCode == mCurrentVirtualKey.keyCode) { // Pointer is still within the space of the virtual key. @@ -3937,15 +4184,15 @@ bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) { } } - if (mLastRawPointerData.touchingIdBits.isEmpty() - && !mCurrentRawPointerData.touchingIdBits.isEmpty()) { + if (mLastRawState.rawPointerData.touchingIdBits.isEmpty() + && !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) { // Pointer just went down. Check for virtual key press or off-screen touches. - uint32_t id = mCurrentRawPointerData.touchingIdBits.firstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); + uint32_t id = mCurrentRawState.rawPointerData.touchingIdBits.firstMarkedBit(); + const RawPointerData::Pointer& pointer = mCurrentRawState.rawPointerData.pointerForId(id); if (!isPointInsideSurface(pointer.x, pointer.y)) { // If exactly one pointer went down, check for virtual key hit. // Otherwise we will drop the entire stroke. - if (mCurrentRawPointerData.touchingIdBits.count() == 1) { + if (mCurrentRawState.rawPointerData.touchingIdBits.count() == 1) { const VirtualKey* virtualKey = findVirtualKeyHit(pointer.x, pointer.y); if (virtualKey) { mCurrentVirtualKey.down = true; @@ -3985,7 +4232,8 @@ bool TouchInputMapper::consumeRawTouches(nsecs_t when, uint32_t policyFlags) { // area and accidentally triggers a virtual key. This often happens when virtual keys // are layed out below the screen near to where the on screen keyboard's space bar // is displayed. - if (mConfig.virtualKeyQuietTime > 0 && !mCurrentRawPointerData.touchingIdBits.isEmpty()) { + if (mConfig.virtualKeyQuietTime > 0 && + !mCurrentRawState.rawPointerData.touchingIdBits.isEmpty()) { mContext->disableVirtualKeysUntil(when + mConfig.virtualKeyQuietTime); } return false; @@ -4005,10 +4253,10 @@ void TouchInputMapper::dispatchVirtualKey(nsecs_t when, uint32_t policyFlags, } void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { - BitSet32 currentIdBits = mCurrentCookedPointerData.touchingIdBits; - BitSet32 lastIdBits = mLastCookedPointerData.touchingIdBits; + BitSet32 currentIdBits = mCurrentCookedState.cookedPointerData.touchingIdBits; + BitSet32 lastIdBits = mLastCookedState.cookedPointerData.touchingIdBits; int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mCurrentButtonState; + int32_t buttonState = mCurrentRawState.buttonState; if (currentIdBits == lastIdBits) { if (!currentIdBits.isEmpty()) { @@ -4017,9 +4265,9 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, currentIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } @@ -4034,14 +4282,14 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { // Update last coordinates of pointers that have moved so that we observe the new // pointer positions at the same time as other pointers that have just gone up. bool moveNeeded = updateMovedPointers( - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - mLastCookedPointerData.pointerProperties, - mLastCookedPointerData.pointerCoords, - mLastCookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mLastCookedState.cookedPointerData.pointerProperties, + mLastCookedState.cookedPointerData.pointerCoords, + mLastCookedState.cookedPointerData.idToIndex, moveIdBits); - if (buttonState != mLastButtonState) { + if (buttonState != mLastRawState.buttonState) { moveNeeded = true; } @@ -4051,9 +4299,9 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_UP, 0, metaState, buttonState, 0, - mLastCookedPointerData.pointerProperties, - mLastCookedPointerData.pointerCoords, - mLastCookedPointerData.idToIndex, + mLastCookedState.cookedPointerData.pointerProperties, + mLastCookedState.cookedPointerData.pointerCoords, + mLastCookedState.cookedPointerData.idToIndex, dispatchedIdBits, upId, mOrientedXPrecision, mOrientedYPrecision, mDownTime); dispatchedIdBits.clearBit(upId); @@ -4066,9 +4314,9 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { ALOG_ASSERT(moveIdBits.value == dispatchedIdBits.value); dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_MOVE, 0, metaState, buttonState, 0, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, dispatchedIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } @@ -4085,9 +4333,9 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_POINTER_DOWN, 0, metaState, buttonState, 0, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, dispatchedIdBits, downId, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } @@ -4096,57 +4344,60 @@ void TouchInputMapper::dispatchTouches(nsecs_t when, uint32_t policyFlags) { void TouchInputMapper::dispatchHoverExit(nsecs_t when, uint32_t policyFlags) { if (mSentHoverEnter && - (mCurrentCookedPointerData.hoveringIdBits.isEmpty() - || !mCurrentCookedPointerData.touchingIdBits.isEmpty())) { + (mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty() + || !mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty())) { int32_t metaState = getContext()->getGlobalMetaState(); dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastButtonState, 0, - mLastCookedPointerData.pointerProperties, - mLastCookedPointerData.pointerCoords, - mLastCookedPointerData.idToIndex, - mLastCookedPointerData.hoveringIdBits, -1, + AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastRawState.buttonState, 0, + mLastCookedState.cookedPointerData.pointerProperties, + mLastCookedState.cookedPointerData.pointerCoords, + mLastCookedState.cookedPointerData.idToIndex, + mLastCookedState.cookedPointerData.hoveringIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); mSentHoverEnter = false; } } void TouchInputMapper::dispatchHoverEnterAndMove(nsecs_t when, uint32_t policyFlags) { - if (mCurrentCookedPointerData.touchingIdBits.isEmpty() - && !mCurrentCookedPointerData.hoveringIdBits.isEmpty()) { + if (mCurrentCookedState.cookedPointerData.touchingIdBits.isEmpty() + && !mCurrentCookedState.cookedPointerData.hoveringIdBits.isEmpty()) { int32_t metaState = getContext()->getGlobalMetaState(); if (!mSentHoverEnter) { - dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, mCurrentButtonState, 0, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - mCurrentCookedPointerData.hoveringIdBits, -1, + dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_HOVER_ENTER, + 0, metaState, mCurrentRawState.buttonState, 0, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.hoveringIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); mSentHoverEnter = true; } dispatchMotion(when, policyFlags, mSource, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, mCurrentButtonState, 0, - mCurrentCookedPointerData.pointerProperties, - mCurrentCookedPointerData.pointerCoords, - mCurrentCookedPointerData.idToIndex, - mCurrentCookedPointerData.hoveringIdBits, -1, + AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, + mCurrentRawState.buttonState, 0, + mCurrentCookedState.cookedPointerData.pointerProperties, + mCurrentCookedState.cookedPointerData.pointerCoords, + mCurrentCookedState.cookedPointerData.idToIndex, + mCurrentCookedState.cookedPointerData.hoveringIdBits, -1, mOrientedXPrecision, mOrientedYPrecision, mDownTime); } } void TouchInputMapper::cookPointerData() { - uint32_t currentPointerCount = mCurrentRawPointerData.pointerCount; + uint32_t currentPointerCount = mCurrentRawState.rawPointerData.pointerCount; - mCurrentCookedPointerData.clear(); - mCurrentCookedPointerData.pointerCount = currentPointerCount; - mCurrentCookedPointerData.hoveringIdBits = mCurrentRawPointerData.hoveringIdBits; - mCurrentCookedPointerData.touchingIdBits = mCurrentRawPointerData.touchingIdBits; + mCurrentCookedState.cookedPointerData.clear(); + mCurrentCookedState.cookedPointerData.pointerCount = currentPointerCount; + mCurrentCookedState.cookedPointerData.hoveringIdBits = + mCurrentRawState.rawPointerData.hoveringIdBits; + mCurrentCookedState.cookedPointerData.touchingIdBits = + mCurrentRawState.rawPointerData.touchingIdBits; // Walk through the the active pointers and map device coordinates onto // surface coordinates and adjust for display orientation. for (uint32_t i = 0; i < currentPointerCount; i++) { - const RawPointerData::Pointer& in = mCurrentRawPointerData.pointers[i]; + const RawPointerData::Pointer& in = mCurrentRawState.rawPointerData.pointers[i]; // Size float touchMajor, touchMinor, toolMajor, toolMinor, size; @@ -4185,7 +4436,8 @@ void TouchInputMapper::cookPointerData() { } if (mCalibration.haveSizeIsSummed && mCalibration.sizeIsSummed) { - uint32_t touchingCount = mCurrentRawPointerData.touchingIdBits.count(); + uint32_t touchingCount = + mCurrentRawState.rawPointerData.touchingIdBits.count(); if (touchingCount > 1) { touchMajor /= touchingCount; touchMinor /= touchingCount; @@ -4354,7 +4606,7 @@ void TouchInputMapper::cookPointerData() { } // Write output coords. - PointerCoords& out = mCurrentCookedPointerData.pointerCoords[i]; + PointerCoords& out = mCurrentCookedState.cookedPointerData.pointerCoords[i]; out.clear(); out.setAxisValue(AMOTION_EVENT_AXIS_X, x); out.setAxisValue(AMOTION_EVENT_AXIS_Y, y); @@ -4376,14 +4628,15 @@ void TouchInputMapper::cookPointerData() { } // Write output properties. - PointerProperties& properties = mCurrentCookedPointerData.pointerProperties[i]; + PointerProperties& properties = + mCurrentCookedState.cookedPointerData.pointerProperties[i]; uint32_t id = in.id; properties.clear(); properties.id = id; properties.toolType = in.toolType; // Write id index. - mCurrentCookedPointerData.idToIndex[id] = i; + mCurrentCookedState.cookedPointerData.idToIndex[id] = i; } } @@ -4487,7 +4740,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag // Send events! int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mCurrentButtonState; + int32_t buttonState = mCurrentRawState.buttonState; // Update last coordinates of pointers that have moved so that we observe the new // pointer positions at the same time as other pointers that have just gone up. @@ -4508,7 +4761,7 @@ void TouchInputMapper::dispatchPointerGestures(nsecs_t when, uint32_t policyFlag mPointerGesture.lastGestureProperties, mPointerGesture.lastGestureCoords, mPointerGesture.lastGestureIdToIndex, movedGestureIdBits); - if (buttonState != mLastButtonState) { + if (buttonState != mLastRawState.buttonState) { moveNeeded = true; } } @@ -4639,7 +4892,7 @@ void TouchInputMapper::abortPointerGestures(nsecs_t when, uint32_t policyFlags) // Cancel previously dispatches pointers. if (!mPointerGesture.lastGestureIdBits.isEmpty()) { int32_t metaState = getContext()->getGlobalMetaState(); - int32_t buttonState = mCurrentButtonState; + int32_t buttonState = mCurrentRawState.buttonState; dispatchMotion(when, policyFlags, mSource, AMOTION_EVENT_ACTION_CANCEL, 0, metaState, buttonState, AMOTION_EVENT_EDGE_FLAG_NONE, @@ -4696,21 +4949,22 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, return false; } - const uint32_t currentFingerCount = mCurrentFingerIdBits.count(); - const uint32_t lastFingerCount = mLastFingerIdBits.count(); + const uint32_t currentFingerCount = mCurrentCookedState.fingerIdBits.count(); + const uint32_t lastFingerCount = mLastCookedState.fingerIdBits.count(); // Update the velocity tracker. { VelocityTracker::Position positions[MAX_POINTERS]; uint32_t count = 0; - for (BitSet32 idBits(mCurrentFingerIdBits); !idBits.isEmpty(); count++) { + for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty(); count++) { uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& pointer = mCurrentRawPointerData.pointerForId(id); + const RawPointerData::Pointer& pointer = + mCurrentRawState.rawPointerData.pointerForId(id); positions[count].x = pointer.x * mPointerXMovementScale; positions[count].y = pointer.y * mPointerYMovementScale; } mPointerGesture.velocityTracker.addMovement(when, - mCurrentFingerIdBits, positions); + mCurrentCookedState.fingerIdBits, positions); } // If the gesture ever enters a mode other than TAP, HOVER or TAP_DRAG, without first returning @@ -4730,17 +4984,17 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, int32_t lastActiveTouchId = mPointerGesture.activeTouchId; int32_t activeTouchId = lastActiveTouchId; if (activeTouchId < 0) { - if (!mCurrentFingerIdBits.isEmpty()) { + if (!mCurrentCookedState.fingerIdBits.isEmpty()) { activeTouchChanged = true; activeTouchId = mPointerGesture.activeTouchId = - mCurrentFingerIdBits.firstMarkedBit(); + mCurrentCookedState.fingerIdBits.firstMarkedBit(); mPointerGesture.firstTouchTime = when; } - } else if (!mCurrentFingerIdBits.hasBit(activeTouchId)) { + } else if (!mCurrentCookedState.fingerIdBits.hasBit(activeTouchId)) { activeTouchChanged = true; - if (!mCurrentFingerIdBits.isEmpty()) { + if (!mCurrentCookedState.fingerIdBits.isEmpty()) { activeTouchId = mPointerGesture.activeTouchId = - mCurrentFingerIdBits.firstMarkedBit(); + mCurrentCookedState.fingerIdBits.firstMarkedBit(); } else { activeTouchId = mPointerGesture.activeTouchId = -1; } @@ -4763,7 +5017,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, isQuietTime = true; } else if (mPointerGesture.lastGestureMode == PointerGesture::BUTTON_CLICK_OR_DRAG && currentFingerCount >= 2 - && !isPointerDown(mCurrentButtonState)) { + && !isPointerDown(mCurrentRawState.buttonState)) { // Enter quiet time when releasing the button and there are still two or more // fingers down. This may indicate that one finger was used to press the button // but it has not gone up yet. @@ -4791,7 +5045,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureIdBits.clear(); mPointerVelocityControl.reset(); - } else if (isPointerDown(mCurrentButtonState)) { + } else if (isPointerDown(mCurrentRawState.buttonState)) { // Case 2: Button is pressed. (BUTTON_CLICK_OR_DRAG) // The pointer follows the active touch point. // Emit DOWN, MOVE, UP events at the pointer location. @@ -4820,7 +5074,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, if (activeTouchId >= 0 && currentFingerCount > 1) { int32_t bestId = -1; float bestSpeed = mConfig.pointerGestureDragMinSwitchSpeed; - for (BitSet32 idBits(mCurrentFingerIdBits); !idBits.isEmpty(); ) { + for (BitSet32 idBits(mCurrentCookedState.fingerIdBits); !idBits.isEmpty(); ) { uint32_t id = idBits.clearFirstMarkedBit(); float vx, vy; if (mPointerGesture.velocityTracker.getVelocity(id, &vx, &vy)) { @@ -4841,11 +5095,11 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } } - if (activeTouchId >= 0 && mLastFingerIdBits.hasBit(activeTouchId)) { + if (activeTouchId >= 0 && mLastCookedState.fingerIdBits.hasBit(activeTouchId)) { const RawPointerData::Pointer& currentPointer = - mCurrentRawPointerData.pointerForId(activeTouchId); + mCurrentRawState.rawPointerData.pointerForId(activeTouchId); const RawPointerData::Pointer& lastPointer = - mLastRawPointerData.pointerForId(activeTouchId); + mLastRawState.rawPointerData.pointerForId(activeTouchId); float deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale; float deltaY = (currentPointer.y - lastPointer.y) * mPointerYMovementScale; @@ -4981,11 +5235,11 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureMode = PointerGesture::TAP_DRAG; } - if (mLastFingerIdBits.hasBit(activeTouchId)) { + if (mLastCookedState.fingerIdBits.hasBit(activeTouchId)) { const RawPointerData::Pointer& currentPointer = - mCurrentRawPointerData.pointerForId(activeTouchId); + mCurrentRawState.rawPointerData.pointerForId(activeTouchId); const RawPointerData::Pointer& lastPointer = - mLastRawPointerData.pointerForId(activeTouchId); + mLastRawState.rawPointerData.pointerForId(activeTouchId); float deltaX = (currentPointer.x - lastPointer.x) * mPointerXMovementScale; float deltaY = (currentPointer.y - lastPointer.y) @@ -5090,7 +5344,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, + mConfig.pointerGestureMultitouchSettleInterval - when) * 0.000001f); #endif - mCurrentRawPointerData.getCentroidOfTouchingPointers( + mCurrentRawState.rawPointerData.getCentroidOfTouchingPointers( &mPointerGesture.referenceTouchX, &mPointerGesture.referenceTouchY); mPointerController->getPosition(&mPointerGesture.referenceGestureX, @@ -5098,23 +5352,23 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } // Clear the reference deltas for fingers not yet included in the reference calculation. - for (BitSet32 idBits(mCurrentFingerIdBits.value + for (BitSet32 idBits(mCurrentCookedState.fingerIdBits.value & ~mPointerGesture.referenceIdBits.value); !idBits.isEmpty(); ) { uint32_t id = idBits.clearFirstMarkedBit(); mPointerGesture.referenceDeltas[id].dx = 0; mPointerGesture.referenceDeltas[id].dy = 0; } - mPointerGesture.referenceIdBits = mCurrentFingerIdBits; + mPointerGesture.referenceIdBits = mCurrentCookedState.fingerIdBits; // Add delta for all fingers and calculate a common movement delta. float commonDeltaX = 0, commonDeltaY = 0; - BitSet32 commonIdBits(mLastFingerIdBits.value - & mCurrentFingerIdBits.value); + BitSet32 commonIdBits(mLastCookedState.fingerIdBits.value + & mCurrentCookedState.fingerIdBits.value); for (BitSet32 idBits(commonIdBits); !idBits.isEmpty(); ) { bool first = (idBits == commonIdBits); uint32_t id = idBits.clearFirstMarkedBit(); - const RawPointerData::Pointer& cpd = mCurrentRawPointerData.pointerForId(id); - const RawPointerData::Pointer& lpd = mLastRawPointerData.pointerForId(id); + const RawPointerData::Pointer& cpd = mCurrentRawState.rawPointerData.pointerForId(id); + const RawPointerData::Pointer& lpd = mLastRawState.rawPointerData.pointerForId(id); PointerGesture::Delta& delta = mPointerGesture.referenceDeltas[id]; delta.dx += cpd.x - lpd.x; delta.dy += cpd.y - lpd.y; @@ -5155,11 +5409,13 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureMode = PointerGesture::FREEFORM; } else { // There are exactly two pointers. - BitSet32 idBits(mCurrentFingerIdBits); + BitSet32 idBits(mCurrentCookedState.fingerIdBits); uint32_t id1 = idBits.clearFirstMarkedBit(); uint32_t id2 = idBits.firstMarkedBit(); - const RawPointerData::Pointer& p1 = mCurrentRawPointerData.pointerForId(id1); - const RawPointerData::Pointer& p2 = mCurrentRawPointerData.pointerForId(id2); + const RawPointerData::Pointer& p1 = + mCurrentRawState.rawPointerData.pointerForId(id1); + const RawPointerData::Pointer& p2 = + mCurrentRawState.rawPointerData.pointerForId(id2); float mutualDistance = distance(p1.x, p1.y, p2.x, p2.y); if (mutualDistance > mPointerGestureMaxSwipeWidth) { // There are two pointers but they are too far apart for a SWIPE, @@ -5305,14 +5561,14 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } else { // Otherwise, assume we mapped all touches from the previous frame. // Reuse all mappings that are still applicable. - mappedTouchIdBits.value = mLastFingerIdBits.value - & mCurrentFingerIdBits.value; + mappedTouchIdBits.value = mLastCookedState.fingerIdBits.value + & mCurrentCookedState.fingerIdBits.value; usedGestureIdBits = mPointerGesture.lastGestureIdBits; // Check whether we need to choose a new active gesture id because the // current went went up. - for (BitSet32 upTouchIdBits(mLastFingerIdBits.value - & ~mCurrentFingerIdBits.value); + for (BitSet32 upTouchIdBits(mLastCookedState.fingerIdBits.value + & ~mCurrentCookedState.fingerIdBits.value); !upTouchIdBits.isEmpty(); ) { uint32_t upTouchId = upTouchIdBits.clearFirstMarkedBit(); uint32_t upGestureId = mPointerGesture.freeformTouchToGestureIdMap[upTouchId]; @@ -5331,7 +5587,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.activeGestureId); #endif - BitSet32 idBits(mCurrentFingerIdBits); + BitSet32 idBits(mCurrentCookedState.fingerIdBits); for (uint32_t i = 0; i < currentFingerCount; i++) { uint32_t touchId = idBits.clearFirstMarkedBit(); uint32_t gestureId; @@ -5355,7 +5611,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, mPointerGesture.currentGestureIdToIndex[gestureId] = i; const RawPointerData::Pointer& pointer = - mCurrentRawPointerData.pointerForId(touchId); + mCurrentRawState.rawPointerData.pointerForId(touchId); float deltaX = (pointer.x - mPointerGesture.referenceTouchX) * mPointerXZoomScale; float deltaY = (pointer.y - mPointerGesture.referenceTouchY) @@ -5386,7 +5642,7 @@ bool TouchInputMapper::preparePointerGestures(nsecs_t when, } } - mPointerController->setButtonState(mCurrentButtonState); + mPointerController->setButtonState(mCurrentRawState.buttonState); #if DEBUG_GESTURES ALOGD("Gestures: finishPreviousGesture=%s, cancelPreviousGesture=%s, " @@ -5428,23 +5684,24 @@ void TouchInputMapper::dispatchPointerStylus(nsecs_t when, uint32_t policyFlags) mPointerSimple.currentProperties.clear(); bool down, hovering; - if (!mCurrentStylusIdBits.isEmpty()) { - uint32_t id = mCurrentStylusIdBits.firstMarkedBit(); - uint32_t index = mCurrentCookedPointerData.idToIndex[id]; - float x = mCurrentCookedPointerData.pointerCoords[index].getX(); - float y = mCurrentCookedPointerData.pointerCoords[index].getY(); + if (!mCurrentCookedState.stylusIdBits.isEmpty()) { + uint32_t id = mCurrentCookedState.stylusIdBits.firstMarkedBit(); + uint32_t index = mCurrentCookedState.cookedPointerData.idToIndex[id]; + float x = mCurrentCookedState.cookedPointerData.pointerCoords[index].getX(); + float y = mCurrentCookedState.cookedPointerData.pointerCoords[index].getY(); mPointerController->setPosition(x, y); - hovering = mCurrentCookedPointerData.hoveringIdBits.hasBit(id); + hovering = mCurrentCookedState.cookedPointerData.hoveringIdBits.hasBit(id); down = !hovering; mPointerController->getPosition(&x, &y); - mPointerSimple.currentCoords.copyFrom(mCurrentCookedPointerData.pointerCoords[index]); + mPointerSimple.currentCoords.copyFrom( + mCurrentCookedState.cookedPointerData.pointerCoords[index]); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); mPointerSimple.currentProperties.id = 0; mPointerSimple.currentProperties.toolType = - mCurrentCookedPointerData.pointerProperties[index].toolType; + mCurrentCookedState.cookedPointerData.pointerProperties[index].toolType; } else { down = false; hovering = false; @@ -5462,16 +5719,16 @@ void TouchInputMapper::dispatchPointerMouse(nsecs_t when, uint32_t policyFlags) mPointerSimple.currentProperties.clear(); bool down, hovering; - if (!mCurrentMouseIdBits.isEmpty()) { - uint32_t id = mCurrentMouseIdBits.firstMarkedBit(); - uint32_t currentIndex = mCurrentRawPointerData.idToIndex[id]; - if (mLastMouseIdBits.hasBit(id)) { - uint32_t lastIndex = mCurrentRawPointerData.idToIndex[id]; - float deltaX = (mCurrentRawPointerData.pointers[currentIndex].x - - mLastRawPointerData.pointers[lastIndex].x) + if (!mCurrentCookedState.mouseIdBits.isEmpty()) { + uint32_t id = mCurrentCookedState.mouseIdBits.firstMarkedBit(); + uint32_t currentIndex = mCurrentRawState.rawPointerData.idToIndex[id]; + if (mLastCookedState.mouseIdBits.hasBit(id)) { + uint32_t lastIndex = mCurrentRawState.rawPointerData.idToIndex[id]; + float deltaX = (mCurrentRawState.rawPointerData.pointers[currentIndex].x + - mLastRawState.rawPointerData.pointers[lastIndex].x) * mPointerXMovementScale; - float deltaY = (mCurrentRawPointerData.pointers[currentIndex].y - - mLastRawPointerData.pointers[lastIndex].y) + float deltaY = (mCurrentRawState.rawPointerData.pointers[currentIndex].y + - mLastRawState.rawPointerData.pointers[lastIndex].y) * mPointerYMovementScale; rotateDelta(mSurfaceOrientation, &deltaX, &deltaY); @@ -5482,20 +5739,20 @@ void TouchInputMapper::dispatchPointerMouse(nsecs_t when, uint32_t policyFlags) mPointerVelocityControl.reset(); } - down = isPointerDown(mCurrentButtonState); + down = isPointerDown(mCurrentRawState.buttonState); hovering = !down; float x, y; mPointerController->getPosition(&x, &y); mPointerSimple.currentCoords.copyFrom( - mCurrentCookedPointerData.pointerCoords[currentIndex]); + mCurrentCookedState.cookedPointerData.pointerCoords[currentIndex]); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_X, x); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_Y, y); mPointerSimple.currentCoords.setAxisValue(AMOTION_EVENT_AXIS_PRESSURE, hovering ? 0.0f : 1.0f); mPointerSimple.currentProperties.id = 0; mPointerSimple.currentProperties.toolType = - mCurrentCookedPointerData.pointerProperties[currentIndex].toolType; + mCurrentCookedState.cookedPointerData.pointerProperties[currentIndex].toolType; } else { mPointerVelocityControl.reset(); @@ -5520,7 +5777,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, if (down || hovering) { mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER); mPointerController->clearSpots(); - mPointerController->setButtonState(mCurrentButtonState); + mPointerController->setButtonState(mCurrentRawState.buttonState); mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE); } else if (!down && !hovering && (mPointerSimple.down || mPointerSimple.hovering)) { mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL); @@ -5532,7 +5789,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, // Send up. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_UP, 0, metaState, mLastButtonState, 0, + AMOTION_EVENT_ACTION_UP, 0, metaState, mLastRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -5545,7 +5802,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, // Send hover exit. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastButtonState, 0, + AMOTION_EVENT_ACTION_HOVER_EXIT, 0, metaState, mLastRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.lastProperties, &mPointerSimple.lastCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -5560,7 +5817,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, // Send down. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_DOWN, 0, metaState, mCurrentButtonState, 0, + AMOTION_EVENT_ACTION_DOWN, 0, metaState, mCurrentRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -5570,7 +5827,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, // Send move. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_MOVE, 0, metaState, mCurrentButtonState, 0, + AMOTION_EVENT_ACTION_MOVE, 0, metaState, mCurrentRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -5584,7 +5841,8 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, // Send hover enter. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, mCurrentButtonState, 0, + AMOTION_EVENT_ACTION_HOVER_ENTER, 0, metaState, + mCurrentRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -5594,7 +5852,8 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, // Send hover move. NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, mCurrentButtonState, 0, + AMOTION_EVENT_ACTION_HOVER_MOVE, 0, metaState, + mCurrentRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.currentProperties, &mPointerSimple.currentCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -5602,9 +5861,9 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, getListener()->notifyMotion(&args); } - if (mCurrentRawVScroll || mCurrentRawHScroll) { - float vscroll = mCurrentRawVScroll; - float hscroll = mCurrentRawHScroll; + if (mCurrentRawState.rawVScroll || mCurrentRawState.rawHScroll) { + float vscroll = mCurrentRawState.rawVScroll; + float hscroll = mCurrentRawState.rawHScroll; mWheelYVelocityControl.move(when, NULL, &vscroll); mWheelXVelocityControl.move(when, &hscroll, NULL); @@ -5615,7 +5874,7 @@ void TouchInputMapper::dispatchPointerSimple(nsecs_t when, uint32_t policyFlags, pointerCoords.setAxisValue(AMOTION_EVENT_AXIS_HSCROLL, hscroll); NotifyMotionArgs args(when, getDeviceId(), mSource, policyFlags, - AMOTION_EVENT_ACTION_SCROLL, 0, metaState, mCurrentButtonState, 0, + AMOTION_EVENT_ACTION_SCROLL, 0, metaState, mCurrentRawState.buttonState, 0, mViewport.displayId, 1, &mPointerSimple.currentProperties, &pointerCoords, mOrientedXPrecision, mOrientedYPrecision, @@ -5717,6 +5976,10 @@ void TouchInputMapper::fadePointer() { } } +void TouchInputMapper::cancelTouch(nsecs_t when) { + abortPointerUsage(when, 0 /*policyFlags*/); +} + bool TouchInputMapper::isPointInsideSurface(int32_t x, int32_t y) { return x >= mRawPointerAxes.x.minValue && x <= mRawPointerAxes.x.maxValue && y >= mRawPointerAxes.y.minValue && y <= mRawPointerAxes.y.maxValue; @@ -5745,11 +6008,11 @@ const TouchInputMapper::VirtualKey* TouchInputMapper::findVirtualKeyHit( return NULL; } -void TouchInputMapper::assignPointerIds() { - uint32_t currentPointerCount = mCurrentRawPointerData.pointerCount; - uint32_t lastPointerCount = mLastRawPointerData.pointerCount; +void TouchInputMapper::assignPointerIds(const RawState* last, RawState* current) { + uint32_t currentPointerCount = current->rawPointerData.pointerCount; + uint32_t lastPointerCount = last->rawPointerData.pointerCount; - mCurrentRawPointerData.clearIdBits(); + current->rawPointerData.clearIdBits(); if (currentPointerCount == 0) { // No pointers to assign. @@ -5760,21 +6023,21 @@ void TouchInputMapper::assignPointerIds() { // All pointers are new. for (uint32_t i = 0; i < currentPointerCount; i++) { uint32_t id = i; - mCurrentRawPointerData.pointers[i].id = id; - mCurrentRawPointerData.idToIndex[id] = i; - mCurrentRawPointerData.markIdBit(id, mCurrentRawPointerData.isHovering(i)); + current->rawPointerData.pointers[i].id = id; + current->rawPointerData.idToIndex[id] = i; + current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(i)); } return; } if (currentPointerCount == 1 && lastPointerCount == 1 - && mCurrentRawPointerData.pointers[0].toolType - == mLastRawPointerData.pointers[0].toolType) { + && current->rawPointerData.pointers[0].toolType + == last->rawPointerData.pointers[0].toolType) { // Only one pointer and no change in count so it must have the same id as before. - uint32_t id = mLastRawPointerData.pointers[0].id; - mCurrentRawPointerData.pointers[0].id = id; - mCurrentRawPointerData.idToIndex[id] = 0; - mCurrentRawPointerData.markIdBit(id, mCurrentRawPointerData.isHovering(0)); + uint32_t id = last->rawPointerData.pointers[0].id; + current->rawPointerData.pointers[0].id = id; + current->rawPointerData.idToIndex[id] = 0; + current->rawPointerData.markIdBit(id, current->rawPointerData.isHovering(0)); return; } @@ -5792,9 +6055,9 @@ void TouchInputMapper::assignPointerIds() { for (uint32_t lastPointerIndex = 0; lastPointerIndex < lastPointerCount; lastPointerIndex++) { const RawPointerData::Pointer& currentPointer = - mCurrentRawPointerData.pointers[currentPointerIndex]; + current->rawPointerData.pointers[currentPointerIndex]; const RawPointerData::Pointer& lastPointer = - mLastRawPointerData.pointers[lastPointerIndex]; + last->rawPointerData.pointers[lastPointerIndex]; if (currentPointer.toolType == lastPointer.toolType) { int64_t deltaX = currentPointer.x - lastPointer.x; int64_t deltaY = currentPointer.y - lastPointer.y; @@ -5900,11 +6163,11 @@ void TouchInputMapper::assignPointerIds() { matchedCurrentBits.markBit(currentPointerIndex); matchedLastBits.markBit(lastPointerIndex); - uint32_t id = mLastRawPointerData.pointers[lastPointerIndex].id; - mCurrentRawPointerData.pointers[currentPointerIndex].id = id; - mCurrentRawPointerData.idToIndex[id] = currentPointerIndex; - mCurrentRawPointerData.markIdBit(id, - mCurrentRawPointerData.isHovering(currentPointerIndex)); + uint32_t id = last->rawPointerData.pointers[lastPointerIndex].id; + current->rawPointerData.pointers[currentPointerIndex].id = id; + current->rawPointerData.idToIndex[id] = currentPointerIndex; + current->rawPointerData.markIdBit(id, + current->rawPointerData.isHovering(currentPointerIndex)); usedIdBits.markBit(id); #if DEBUG_POINTER_ASSIGNMENT @@ -5920,10 +6183,10 @@ void TouchInputMapper::assignPointerIds() { uint32_t currentPointerIndex = matchedCurrentBits.markFirstUnmarkedBit(); uint32_t id = usedIdBits.markFirstUnmarkedBit(); - mCurrentRawPointerData.pointers[currentPointerIndex].id = id; - mCurrentRawPointerData.idToIndex[id] = currentPointerIndex; - mCurrentRawPointerData.markIdBit(id, - mCurrentRawPointerData.isHovering(currentPointerIndex)); + current->rawPointerData.pointers[currentPointerIndex].id = id; + current->rawPointerData.idToIndex[id] = currentPointerIndex; + current->rawPointerData.markIdBit(id, + current->rawPointerData.isHovering(currentPointerIndex)); #if DEBUG_POINTER_ASSIGNMENT ALOGD("assignPointerIds - assigned: cur=%d, id=%d", @@ -6002,18 +6265,18 @@ void SingleTouchInputMapper::process(const RawEvent* rawEvent) { mSingleTouchMotionAccumulator.process(rawEvent); } -void SingleTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) { +void SingleTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { if (mTouchButtonAccumulator.isToolActive()) { - mCurrentRawPointerData.pointerCount = 1; - mCurrentRawPointerData.idToIndex[0] = 0; + outState->rawPointerData.pointerCount = 1; + outState->rawPointerData.idToIndex[0] = 0; bool isHovering = mTouchButtonAccumulator.getToolType() != AMOTION_EVENT_TOOL_TYPE_MOUSE && (mTouchButtonAccumulator.isHovering() || (mRawPointerAxes.pressure.valid && mSingleTouchMotionAccumulator.getAbsolutePressure() <= 0)); - mCurrentRawPointerData.markIdBit(0, isHovering); + outState->rawPointerData.markIdBit(0, isHovering); - RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[0]; + RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[0]; outPointer.id = 0; outPointer.x = mSingleTouchMotionAccumulator.getAbsoluteX(); outPointer.y = mSingleTouchMotionAccumulator.getAbsoluteY(); @@ -6074,7 +6337,7 @@ void MultiTouchInputMapper::process(const RawEvent* rawEvent) { mMultiTouchMotionAccumulator.process(rawEvent); } -void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) { +void MultiTouchInputMapper::syncTouch(nsecs_t when, RawState* outState) { size_t inCount = mMultiTouchMotionAccumulator.getSlotCount(); size_t outCount = 0; BitSet32 newPointerIdBits; @@ -6095,7 +6358,7 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) { break; // too many fingers! } - RawPointerData::Pointer& outPointer = mCurrentRawPointerData.pointers[outCount]; + RawPointerData::Pointer& outPointer = outState->rawPointerData.pointers[outCount]; outPointer.x = inSlot->getX(); outPointer.y = inSlot->getY(); outPointer.pressure = inSlot->getPressure(); @@ -6122,38 +6385,37 @@ void MultiTouchInputMapper::syncTouch(nsecs_t when, bool* outHavePointerIds) { outPointer.isHovering = isHovering; // Assign pointer id using tracking id if available. - if (*outHavePointerIds) { - int32_t trackingId = inSlot->getTrackingId(); - int32_t id = -1; - if (trackingId >= 0) { - for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) { - uint32_t n = idBits.clearFirstMarkedBit(); - if (mPointerTrackingIdMap[n] == trackingId) { - id = n; - } - } - - if (id < 0 && !mPointerIdBits.isFull()) { - id = mPointerIdBits.markFirstUnmarkedBit(); - mPointerTrackingIdMap[id] = trackingId; + mHavePointerIds = true; + int32_t trackingId = inSlot->getTrackingId(); + int32_t id = -1; + if (trackingId >= 0) { + for (BitSet32 idBits(mPointerIdBits); !idBits.isEmpty(); ) { + uint32_t n = idBits.clearFirstMarkedBit(); + if (mPointerTrackingIdMap[n] == trackingId) { + id = n; } } - if (id < 0) { - *outHavePointerIds = false; - mCurrentRawPointerData.clearIdBits(); - newPointerIdBits.clear(); - } else { - outPointer.id = id; - mCurrentRawPointerData.idToIndex[id] = outCount; - mCurrentRawPointerData.markIdBit(id, isHovering); - newPointerIdBits.markBit(id); + + if (id < 0 && !mPointerIdBits.isFull()) { + id = mPointerIdBits.markFirstUnmarkedBit(); + mPointerTrackingIdMap[id] = trackingId; } } + if (id < 0) { + mHavePointerIds = false; + outState->rawPointerData.clearIdBits(); + newPointerIdBits.clear(); + } else { + outPointer.id = id; + outState->rawPointerData.idToIndex[id] = outCount; + outState->rawPointerData.markIdBit(id, isHovering); + newPointerIdBits.markBit(id); + } outCount += 1; } - mCurrentRawPointerData.pointerCount = outCount; + outState->rawPointerData.pointerCount = outCount; mPointerIdBits = newPointerIdBits; mMultiTouchMotionAccumulator.finishSync(); @@ -6197,6 +6459,77 @@ bool MultiTouchInputMapper::hasStylus() const { || mTouchButtonAccumulator.hasStylus(); } +// --- ExternalStylusInputMapper + +ExternalStylusInputMapper::ExternalStylusInputMapper(InputDevice* device) : + InputMapper(device) { + +} + +uint32_t ExternalStylusInputMapper::getSources() { + return AINPUT_SOURCE_STYLUS; +} + +void ExternalStylusInputMapper::populateDeviceInfo(InputDeviceInfo* info) { + InputMapper::populateDeviceInfo(info); + info->addMotionRange(AMOTION_EVENT_AXIS_PRESSURE, AINPUT_SOURCE_STYLUS, + 0.0f, 1.0f, 0.0f, 0.0f, 0.0f); +} + +void ExternalStylusInputMapper::dump(String8& dump) { + dump.append(INDENT2 "External Stylus Input Mapper:\n"); + dump.append(INDENT3 "Raw Stylus Axes:\n"); + dumpRawAbsoluteAxisInfo(dump, mRawPressureAxis, "Pressure"); + dump.append(INDENT3 "Stylus State:\n"); + dumpStylusState(dump, mStylusState); +} + +void ExternalStylusInputMapper::configure(nsecs_t when, + const InputReaderConfiguration* config, uint32_t changes) { + getAbsoluteAxisInfo(ABS_PRESSURE, &mRawPressureAxis); + mTouchButtonAccumulator.configure(getDevice()); +} + +void ExternalStylusInputMapper::reset(nsecs_t when) { + InputDevice* device = getDevice(); + mSingleTouchMotionAccumulator.reset(device); + mTouchButtonAccumulator.reset(device); + InputMapper::reset(when); +} + +void ExternalStylusInputMapper::process(const RawEvent* rawEvent) { + mSingleTouchMotionAccumulator.process(rawEvent); + mTouchButtonAccumulator.process(rawEvent); + + if (rawEvent->type == EV_SYN && rawEvent->code == SYN_REPORT) { + sync(rawEvent->when); + } +} + +void ExternalStylusInputMapper::sync(nsecs_t when) { + mStylusState.clear(); + + mStylusState.when = when; + + mStylusState.toolType = mTouchButtonAccumulator.getToolType(); + if (mStylusState.toolType == AMOTION_EVENT_TOOL_TYPE_UNKNOWN) { + mStylusState.toolType = AMOTION_EVENT_TOOL_TYPE_STYLUS; + } + + int32_t pressure = mSingleTouchMotionAccumulator.getAbsolutePressure(); + if (mRawPressureAxis.valid) { + mStylusState.pressure = float(pressure) / mRawPressureAxis.maxValue; + } else if (mTouchButtonAccumulator.isToolActive()) { + mStylusState.pressure = 1.0f; + } else { + mStylusState.pressure = 0.0f; + } + + mStylusState.buttons = mTouchButtonAccumulator.getButtonState(); + + mContext->dispatchExternalStylusState(mStylusState); +} + // --- JoystickInputMapper --- diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h index c5896d4..451a20f 100644 --- a/services/inputflinger/InputReader.h +++ b/services/inputflinger/InputReader.h @@ -139,7 +139,10 @@ struct InputReaderConfiguration { CHANGE_DEVICE_ALIAS = 1 << 5, // The location calibration matrix changed. - TOUCH_AFFINE_TRANSFORMATION = 1 << 6, + CHANGE_TOUCH_AFFINE_TRANSFORMATION = 1 << 6, + + // The presence of an external stylus has changed. + CHANGE_EXTERNAL_STYLUS_PRESENCE = 1 << 7, // All devices must be reopened. CHANGE_MUST_REOPEN = 1 << 31, @@ -371,6 +374,31 @@ public: virtual void cancelVibrate(int32_t deviceId, int32_t token) = 0; }; +struct StylusState { + /* Time the stylus event was received. */ + nsecs_t when; + /* Pressure as reported by the stylus, normalized to the range [0, 1.0]. */ + float pressure; + /* The state of the stylus buttons as a bitfield (e.g. AMOTION_EVENT_BUTTON_SECONDARY). */ + uint32_t buttons; + /* Which tool type the stylus is currently using (e.g. AMOTION_EVENT_TOOL_TYPE_ERASER). */ + int32_t toolType; + + void copyFrom(const StylusState& other) { + when = other.when; + pressure = other.pressure; + buttons = other.buttons; + toolType = other.toolType; + } + + void clear() { + when = LLONG_MAX; + pressure = 0.f; + buttons = 0; + toolType = AMOTION_EVENT_TOOL_TYPE_UNKNOWN; + } +}; + /* Internal interface used by individual input devices to access global input device state * and parameters maintained by the input reader. @@ -392,6 +420,9 @@ public: virtual void requestTimeoutAtTime(nsecs_t when) = 0; virtual int32_t bumpGeneration() = 0; + virtual void getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices) = 0; + virtual void dispatchExternalStylusState(const StylusState& outState) = 0; + virtual InputReaderPolicyInterface* getPolicy() = 0; virtual InputListenerInterface* getListener() = 0; virtual EventHubInterface* getEventHub() = 0; @@ -458,6 +489,8 @@ protected: virtual void fadePointer(); virtual void requestTimeoutAtTime(nsecs_t when); virtual int32_t bumpGeneration(); + virtual void getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices); + virtual void dispatchExternalStylusState(const StylusState& outState); virtual InputReaderPolicyInterface* getPolicy(); virtual InputListenerInterface* getListener(); virtual EventHubInterface* getEventHub(); @@ -496,6 +529,10 @@ private: void updateGlobalMetaStateLocked(); int32_t getGlobalMetaStateLocked(); + void notifyExternalStylusPresenceChanged(); + void getExternalStylusDevicesLocked(Vector<InputDeviceInfo>& outDevices); + void dispatchExternalStylusState(const StylusState& state); + void fadePointerLocked(); int32_t mGeneration; @@ -555,6 +592,9 @@ public: inline bool isExternal() { return mIsExternal; } inline void setExternal(bool external) { mIsExternal = external; } + inline void setMic(bool hasMic) { mHasMic = hasMic; } + inline bool hasMic() const { return mHasMic; } + inline bool isIgnored() { return mMappers.isEmpty(); } void dump(String8& dump); @@ -563,6 +603,7 @@ public: void reset(nsecs_t when); void process(const RawEvent* rawEvents, size_t count); void timeoutExpired(nsecs_t when); + void updateExternalStylusState(const StylusState& state); void getDeviceInfo(InputDeviceInfo* outDeviceInfo); int32_t getKeyCodeState(uint32_t sourceMask, int32_t keyCode); @@ -572,6 +613,7 @@ public: const int32_t* keyCodes, uint8_t* outFlags); void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token); void cancelVibrate(int32_t token); + void cancelTouch(nsecs_t when); int32_t getMetaState(); @@ -617,6 +659,7 @@ private: uint32_t mSources; bool mIsExternal; + bool mHasMic; bool mDropUntilNextSync; typedef int32_t (InputMapper::*GetStateFunc)(uint32_t sourceMask, int32_t code); @@ -830,9 +873,21 @@ struct CookedPointerData { return pointerCoords[idToIndex[id]]; } + inline PointerCoords& editPointerCoordsWithId(uint32_t id) { + return pointerCoords[idToIndex[id]]; + } + + inline PointerProperties& editPointerPropertiesWithId(uint32_t id) { + return pointerProperties[idToIndex[id]]; + } + inline bool isHovering(uint32_t pointerIndex) { return hoveringIdBits.hasBit(pointerProperties[pointerIndex].id); } + + inline bool isTouching(uint32_t pointerIndex) { + return touchingIdBits.hasBit(pointerProperties[pointerIndex].id); + } }; @@ -973,9 +1028,12 @@ public: virtual void vibrate(const nsecs_t* pattern, size_t patternSize, ssize_t repeat, int32_t token); virtual void cancelVibrate(int32_t token); + virtual void cancelTouch(nsecs_t when); virtual int32_t getMetaState(); + virtual void updateExternalStylusState(const StylusState& state); + virtual void fadePointer(); protected: @@ -987,6 +1045,7 @@ protected: static void dumpRawAbsoluteAxisInfo(String8& dump, const RawAbsoluteAxisInfo& axis, const char* name); + static void dumpStylusState(String8& dump, const StylusState& state); }; @@ -1191,7 +1250,9 @@ public: const int32_t* keyCodes, uint8_t* outFlags); virtual void fadePointer(); + virtual void cancelTouch(nsecs_t when); virtual void timeoutExpired(nsecs_t when); + virtual void updateExternalStylusState(const StylusState& state); protected: CursorButtonAccumulator mCursorButtonAccumulator; @@ -1331,36 +1392,79 @@ protected: // Affine location transformation/calibration struct TouchAffineTransformation mAffineTransform; - // Raw pointer axis information from the driver. RawPointerAxes mRawPointerAxes; - // Raw pointer sample data. - RawPointerData mCurrentRawPointerData; - RawPointerData mLastRawPointerData; + struct RawState { + nsecs_t when; - // Cooked pointer sample data. - CookedPointerData mCurrentCookedPointerData; - CookedPointerData mLastCookedPointerData; + // Raw pointer sample data. + RawPointerData rawPointerData; - // Button state. - int32_t mCurrentButtonState; - int32_t mLastButtonState; + int32_t buttonState; - // Scroll state. - int32_t mCurrentRawVScroll; - int32_t mCurrentRawHScroll; + // Scroll state. + int32_t rawVScroll; + int32_t rawHScroll; - // Id bits used to differentiate fingers, stylus and mouse tools. - BitSet32 mCurrentFingerIdBits; // finger or unknown - BitSet32 mLastFingerIdBits; - BitSet32 mCurrentStylusIdBits; // stylus or eraser - BitSet32 mLastStylusIdBits; - BitSet32 mCurrentMouseIdBits; // mouse or lens - BitSet32 mLastMouseIdBits; + void copyFrom(const RawState& other) { + when = other.when; + rawPointerData.copyFrom(other.rawPointerData); + buttonState = other.buttonState; + rawVScroll = other.rawVScroll; + rawHScroll = other.rawHScroll; + } + + void clear() { + when = 0; + rawPointerData.clear(); + buttonState = 0; + rawVScroll = 0; + rawHScroll = 0; + } + }; + + struct CookedState { + // Cooked pointer sample data. + CookedPointerData cookedPointerData; + + // Id bits used to differentiate fingers, stylus and mouse tools. + BitSet32 fingerIdBits; + BitSet32 stylusIdBits; + BitSet32 mouseIdBits; + + void copyFrom(const CookedState& other) { + cookedPointerData.copyFrom(other.cookedPointerData); + fingerIdBits = other.fingerIdBits; + stylusIdBits = other.stylusIdBits; + mouseIdBits = other.mouseIdBits; + } + + void clear() { + cookedPointerData.clear(); + fingerIdBits.clear(); + stylusIdBits.clear(); + mouseIdBits.clear(); + } + }; + + Vector<RawState> mRawStatesPending; + RawState mCurrentRawState; + CookedState mCurrentCookedState; + RawState mLastRawState; + CookedState mLastCookedState; + + // State provided by an external stylus + StylusState mExternalStylusState; + int64_t mExternalStylusId; + nsecs_t mExternalStylusDataTimeout; + bool mExternalStylusDataPending; // True if we sent a HOVER_ENTER event. bool mSentHoverEnter; + // Have we assigned pointer IDs for this stream + bool mHavePointerIds; + // The time the primary pointer last went down. nsecs_t mDownTime; @@ -1380,11 +1484,13 @@ protected: virtual void parseCalibration(); virtual void resolveCalibration(); virtual void dumpCalibration(String8& dump); + virtual void updateAffineTransformation(); virtual void dumpAffineTransformation(String8& dump); + virtual void resolveExternalStylusPresence(); virtual bool hasStylus() const = 0; - virtual void updateAffineTransformation(); + virtual bool hasExternalStylus() const; - virtual void syncTouch(nsecs_t when, bool* outHavePointerIds) = 0; + virtual void syncTouch(nsecs_t when, RawState* outState) = 0; private: // The current viewport. @@ -1430,6 +1536,8 @@ private: float mTiltYCenter; float mTiltYScale; + bool mExternalStylusConnected; + // Oriented motion ranges for input device info. struct OrientedRanges { InputDeviceInfo::MotionRange x; @@ -1672,9 +1780,13 @@ private: VelocityControl mWheelXVelocityControl; VelocityControl mWheelYVelocityControl; + void resetExternalStylus(); + void sync(nsecs_t when); bool consumeRawTouches(nsecs_t when, uint32_t policyFlags); + void processRawTouches(bool timeout); + void cookAndDispatch(nsecs_t when); void dispatchVirtualKey(nsecs_t when, uint32_t policyFlags, int32_t keyEventAction, int32_t keyEventFlags); @@ -1702,6 +1814,10 @@ private: bool down, bool hovering); void abortPointerSimple(nsecs_t when, uint32_t policyFlags); + bool assignExternalStylusId(const RawState& state, bool timeout); + void applyExternalStylusButtonState(nsecs_t when); + void applyExternalStylusTouchState(nsecs_t when); + // Dispatches a motion event. // If the changedId is >= 0 and the action is POINTER_DOWN or POINTER_UP, the // method will take care of setting the index and transmuting the action to DOWN or UP @@ -1723,7 +1839,7 @@ private: bool isPointInsideSurface(int32_t x, int32_t y); const VirtualKey* findVirtualKeyHit(int32_t x, int32_t y); - void assignPointerIds(); + static void assignPointerIds(const RawState* last, RawState* current); }; @@ -1736,7 +1852,7 @@ public: virtual void process(const RawEvent* rawEvent); protected: - virtual void syncTouch(nsecs_t when, bool* outHavePointerIds); + virtual void syncTouch(nsecs_t when, RawState* outState); virtual void configureRawPointerAxes(); virtual bool hasStylus() const; @@ -1754,7 +1870,7 @@ public: virtual void process(const RawEvent* rawEvent); protected: - virtual void syncTouch(nsecs_t when, bool* outHavePointerIds); + virtual void syncTouch(nsecs_t when, RawState* outState); virtual void configureRawPointerAxes(); virtual bool hasStylus() const; @@ -1766,6 +1882,27 @@ private: int32_t mPointerTrackingIdMap[MAX_POINTER_ID + 1]; }; +class ExternalStylusInputMapper : public InputMapper { +public: + ExternalStylusInputMapper(InputDevice* device); + virtual ~ExternalStylusInputMapper() = default; + + virtual uint32_t getSources(); + virtual void populateDeviceInfo(InputDeviceInfo* deviceInfo); + virtual void dump(String8& dump); + virtual void configure(nsecs_t when, const InputReaderConfiguration* config, uint32_t changes); + virtual void reset(nsecs_t when); + virtual void process(const RawEvent* rawEvent); + virtual void sync(nsecs_t when); + +private: + SingleTouchMotionAccumulator mSingleTouchMotionAccumulator; + RawAbsoluteAxisInfo mRawPressureAxis; + TouchButtonAccumulator mTouchButtonAccumulator; + + StylusState mStylusState; +}; + class JoystickInputMapper : public InputMapper { public: diff --git a/services/inputflinger/host/Android.mk b/services/inputflinger/host/Android.mk new file mode 100644 index 0000000..b828175 --- /dev/null +++ b/services/inputflinger/host/Android.mk @@ -0,0 +1,62 @@ +# Copyright (C) 2015 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. + +LOCAL_PATH:= $(call my-dir) +include $(CLEAR_VARS) + +LOCAL_CLANG := true + +LOCAL_SRC_FILES:= \ + InputFlinger.cpp \ + InputDriver.cpp \ + InputHost.cpp + +LOCAL_SHARED_LIBRARIES := \ + libbinder \ + libcrypto \ + libcutils \ + libinput \ + liblog \ + libutils \ + libhardware + + +# TODO: Move inputflinger to its own process and mark it hidden +#LOCAL_CFLAGS += -fvisibility=hidden + +LOCAL_CFLAGS += -Wno-unused-parameter + +LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH) + +LOCAL_MODULE := libinputflingerhost + +include $(BUILD_SHARED_LIBRARY) + +######################################################################## +# build input flinger executable +include $(CLEAR_VARS) + +LOCAL_CLANG := true + +LOCAL_SRC_FILES:= \ + main.cpp + +LOCAL_SHARED_LIBRARIES := \ + libbinder \ + libinputflingerhost \ + libutils + +LOCAL_MODULE := inputflinger + +include $(BUILD_EXECUTABLE) diff --git a/services/inputflinger/host/InputDriver.cpp b/services/inputflinger/host/InputDriver.cpp new file mode 100644 index 0000000..630a596 --- /dev/null +++ b/services/inputflinger/host/InputDriver.cpp @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2015 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. + */ + +#include <stdint.h> +#include <sys/types.h> + +#define LOG_TAG "InputDriver" + +#define LOG_NDEBUG 0 + +#include "InputDriver.h" +#include "InputHost.h" + +#include <hardware/input.h> +#include <utils/Log.h> +#include <utils/String8.h> + +#define INDENT2 " " + +namespace android { + +static input_host_callbacks_t kCallbacks = { + .create_device_identifier = create_device_identifier, + .create_device_definition = create_device_definition, + .create_input_report_definition = create_input_report_definition, + .create_output_report_definition = create_output_report_definition, + .input_device_definition_add_report = input_device_definition_add_report, + .input_report_definition_add_collection = input_report_definition_add_collection, + .input_report_definition_declare_usage_int = input_report_definition_declare_usage_int, + .input_report_definition_declare_usages_bool = input_report_definition_declare_usages_bool, + .register_device = register_device, + .input_allocate_report = input_allocate_report, + .input_report_set_usage_int = input_report_set_usage_int, + .input_report_set_usage_bool = input_report_set_usage_bool, + .report_event = report_event, + .input_get_device_property_map = input_get_device_property_map, + .input_get_device_property = input_get_device_property, + .input_get_property_key = input_get_property_key, + .input_get_property_value = input_get_property_value, + .input_free_device_property = input_free_device_property, + .input_free_device_property_map = input_free_device_property_map, +}; + +InputDriver::InputDriver(const char* name) : mName(String8(name)) { + const hw_module_t* module; + int err = input_open(&module, name); + LOG_ALWAYS_FATAL_IF(err != 0, "Input module %s not found", name); + mHal = reinterpret_cast<const input_module_t*>(module); +} + +void InputDriver::init(InputHostInterface* host) { + mHal->init(mHal, static_cast<input_host_t*>(host), kCallbacks); +} + +void InputDriver::dump(String8& result) { + result.appendFormat(INDENT2 "HAL Input Driver (%s)\n", mName.string()); +} + + +// HAL wrapper functions + +input_device_identifier_t* create_device_identifier(input_host_t* host, + const char* name, int32_t product_id, int32_t vendor_id, + input_bus_t bus, const char* unique_id) { + return nullptr; +} + +input_device_definition_t* create_device_definition(input_host_t* host) { + return nullptr; +} + +input_report_definition_t* create_input_report_definition(input_host_t* host) { + return nullptr; +} + +input_report_definition_t* create_output_report_definition(input_host_t* host) { + return nullptr; +} + +void input_device_definition_add_report(input_host_t* host, + input_device_definition_t* d, input_report_definition_t* r) { } + +void input_report_definition_add_collection(input_host_t* host, + input_report_definition_t* report, input_collection_id_t id, int32_t arity) { } + +void input_report_definition_declare_usage_int(input_host_t* host, + input_report_definition_t* report, input_collection_id_t id, + input_usage_t usage, int32_t min, int32_t max, float resolution) { } + +void input_report_definition_declare_usages_bool(input_host_t* host, + input_report_definition_t* report, input_collection_id_t id, + input_usage_t* usage, size_t usage_count) { } + + +input_device_handle_t* register_device(input_host_t* host, + input_device_identifier_t* id, input_device_definition_t* d) { + return nullptr; +} + +input_report_t* input_allocate_report(input_host_t* host, input_report_definition_t* r) { + return nullptr; +} +void input_report_set_usage_int(input_host_t* host, input_report_t* r, + input_collection_id_t id, input_usage_t usage, int32_t value, int32_t arity_index) { } + +void input_report_set_usage_bool(input_host_t* host, input_report_t* r, + input_collection_id_t id, input_usage_t usage, bool value, int32_t arity_index) { } + +void report_event(input_host_t* host, input_device_handle_t* d, input_report_t* report) { } + +input_property_map_t* input_get_device_property_map(input_host_t* host, + input_device_identifier_t* id) { + return nullptr; +} + +input_property_t* input_get_device_property(input_host_t* host, input_property_map_t* map, + const char* key) { + return nullptr; +} + +const char* input_get_property_key(input_host_t* host, input_property_t* property) { + return nullptr; +} + +const char* input_get_property_value(input_host_t* host, input_property_t* property) { + return nullptr; +} + +void input_free_device_property(input_host_t* host, input_property_t* property) { } + +void input_free_device_property_map(input_host_t* host, input_property_map_t* map) { } + +} // namespace android diff --git a/services/inputflinger/host/InputDriver.h b/services/inputflinger/host/InputDriver.h new file mode 100644 index 0000000..7734ac2 --- /dev/null +++ b/services/inputflinger/host/InputDriver.h @@ -0,0 +1,117 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef ANDROID_INPUT_DRIVER_H +#define ANDROID_INPUT_DRIVER_H + +#include <stdint.h> +#include <sys/types.h> + +#include "InputHost.h" + +#include <hardware/input.h> +#include <utils/RefBase.h> +#include <utils/String8.h> + +namespace android { + +class InputHostInterface; + +class InputDriverInterface : public virtual RefBase { +protected: + InputDriverInterface() = default; + virtual ~InputDriverInterface() = default; + +public: + virtual void init(InputHostInterface* host) = 0; + + virtual void dump(String8& result) = 0; +}; + +class InputDriver : public InputDriverInterface { +public: + InputDriver(const char* name); + virtual ~InputDriver() = default; + + virtual void init(InputHostInterface* host) override; + + virtual void dump(String8& result) override; + +private: + String8 mName; + const input_module_t* mHal; +}; + + +extern "C" { + +input_device_identifier_t* create_device_identifier(input_host_t* host, + const char* name, int32_t product_id, int32_t vendor_id, + input_bus_t bus, const char* unique_id); + +input_device_definition_t* create_device_definition(input_host_t* host); + +input_report_definition_t* create_input_report_definition(input_host_t* host); + +input_report_definition_t* create_output_report_definition(input_host_t* host); + +void input_device_definition_add_report(input_host_t* host, + input_device_definition_t* d, input_report_definition_t* r); + +void input_report_definition_add_collection(input_host_t* host, + input_report_definition_t* report, input_collection_id_t id, int32_t arity); + +void input_report_definition_declare_usage_int(input_host_t* host, + input_report_definition_t* report, input_collection_id_t id, + input_usage_t usage, int32_t min, int32_t max, float resolution); + +void input_report_definition_declare_usages_bool(input_host_t* host, + input_report_definition_t* report, input_collection_id_t id, + input_usage_t* usage, size_t usage_count); + + +input_device_handle_t* register_device(input_host_t* host, + input_device_identifier_t* id, input_device_definition_t* d); + +void unregister_device(input_host_t* host, input_device_handle_t* handle); + +input_report_t* input_allocate_report(input_host_t* host, input_report_definition_t* r); + +void input_report_set_usage_int(input_host_t* host, input_report_t* r, + input_collection_id_t id, input_usage_t usage, int32_t value, int32_t arity_index); + +void input_report_set_usage_bool(input_host_t* host, input_report_t* r, + input_collection_id_t id, input_usage_t usage, bool value, int32_t arity_index); + +void report_event(input_host_t* host, input_device_handle_t* d, input_report_t* report); + +input_property_map_t* input_get_device_property_map(input_host_t* host, + input_device_identifier_t* id); + +input_property_t* input_get_device_property(input_host_t* host, input_property_map_t* map, + const char* key); + +const char* input_get_property_key(input_host_t* host, input_property_t* property); + +const char* input_get_property_value(input_host_t* host, input_property_t* property); + +void input_free_device_property(input_host_t* host, input_property_t* property); + +void input_free_device_property_map(input_host_t* host, input_property_map_t* map); +} + +} // namespace android +#endif // ANDROID_INPUT_DRIVER_H diff --git a/services/inputflinger/host/InputFlinger.cpp b/services/inputflinger/host/InputFlinger.cpp new file mode 100644 index 0000000..859c3b8 --- /dev/null +++ b/services/inputflinger/host/InputFlinger.cpp @@ -0,0 +1,71 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#define LOG_TAG "InputFlinger" + + +#include <stdint.h> +#include <unistd.h> + +#include <sys/types.h> + +#include "InputFlinger.h" +#include "InputDriver.h" + +#include <binder/IPCThreadState.h> +#include <binder/PermissionCache.h> +#include <hardware/input.h> +#include <cutils/log.h> +#include <private/android_filesystem_config.h> + +namespace android { + +const String16 sAccessInputFlingerPermission("android.permission.ACCESS_INPUT_FLINGER"); +const String16 sDumpPermission("android.permission.DUMP"); + + +InputFlinger::InputFlinger() : + BnInputFlinger() { + ALOGI("InputFlinger is starting"); + mHost = new InputHost(); + mHost->registerInputDriver(new InputDriver(INPUT_INSTANCE_EVDEV)); +} + +InputFlinger::~InputFlinger() { +} + +status_t InputFlinger::dump(int fd, const Vector<String16>& args) { + String8 result; + const IPCThreadState* ipc = IPCThreadState::self(); + const int pid = ipc->getCallingPid(); + const int uid = ipc->getCallingUid(); + if ((uid != AID_SHELL) + && !PermissionCache::checkPermission(sDumpPermission, pid, uid)) { + result.appendFormat("Permission Denial: " + "can't dump SurfaceFlinger from pid=%d, uid=%d\n", pid, uid); + } else { + dumpInternal(result); + } + write(fd, result.string(), result.size()); + return OK; +} + +void InputFlinger::dumpInternal(String8& result) { + result.append("INPUT FLINGER (dumpsys inputflinger)\n"); + mHost->dump(result); +} + +}; // namespace android diff --git a/services/inputflinger/host/InputFlinger.h b/services/inputflinger/host/InputFlinger.h new file mode 100644 index 0000000..39e69e5 --- /dev/null +++ b/services/inputflinger/host/InputFlinger.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ANDROID_INPUT_FLINGER_H +#define ANDROID_INPUT_FLINGER_H + +#include <stdint.h> +#include <sys/types.h> + +#include "InputHost.h" + +#include <cutils/compiler.h> +#include <input/IInputFlinger.h> +#include <utils/String8.h> +#include <utils/String16.h> +#include <utils/StrongPointer.h> + +namespace android { + +class InputFlinger : public BnInputFlinger { +public: + static char const* getServiceName() ANDROID_API { + return "inputflinger"; + } + + InputFlinger() ANDROID_API; + + virtual status_t dump(int fd, const Vector<String16>& args); + +private: + virtual ~InputFlinger(); + + void dumpInternal(String8& result); + + sp<InputHostInterface> mHost; +}; + +} // namespace android + +#endif // ANDROID_INPUT_FLINGER_H diff --git a/services/inputflinger/host/InputHost.cpp b/services/inputflinger/host/InputHost.cpp new file mode 100644 index 0000000..51d3e6b --- /dev/null +++ b/services/inputflinger/host/InputHost.cpp @@ -0,0 +1,42 @@ +/* + * Copyright (C) 2015 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. + */ + +#include <vector> + +#include "InputDriver.h" +#include "InputHost.h" + +#include <utils/Log.h> +#include <utils/String8.h> + +#define INDENT " " + +namespace android { + +void InputHost::registerInputDriver(InputDriverInterface* driver) { + LOG_ALWAYS_FATAL_IF(driver == nullptr, "Cannot register a nullptr as an InputDriver!"); + driver->init(this); + mDrivers.push_back(driver); +} + +void InputHost::dump(String8& result) { + result.append(INDENT "Input Drivers:\n"); + for (size_t i = 0; i < mDrivers.size(); i++) { + mDrivers[i]->dump(result); + } +} + +} // namespace android diff --git a/services/inputflinger/host/InputHost.h b/services/inputflinger/host/InputHost.h new file mode 100644 index 0000000..42a66e0 --- /dev/null +++ b/services/inputflinger/host/InputHost.h @@ -0,0 +1,62 @@ +/* + * Copyright (C) 2015 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. + */ + +#ifndef ANDROID_INPUT_HOST_H +#define ANDROID_INPUT_HOST_H + +#include <vector> + +#include <hardware/input.h> +#include <utils/RefBase.h> +#include <utils/String8.h> +#include <utils/StrongPointer.h> + +#include "InputDriver.h" + +// Declare a concrete type for the HAL +struct input_host { +}; + +namespace android { + +class InputDriverInterface; + +class InputHostInterface : public input_host_t, public virtual RefBase { +protected: + InputHostInterface() = default; + virtual ~InputHostInterface() = default; + +public: + + virtual void registerInputDriver(InputDriverInterface* driver) = 0; + + virtual void dump(String8& result) = 0; +}; + +class InputHost : public InputHostInterface { +public: + InputHost() = default; + + virtual void registerInputDriver(InputDriverInterface* driver) override; + + virtual void dump(String8& result) override; + +private: + std::vector<sp<InputDriverInterface>> mDrivers; +}; + +} // namespace android +#endif // ANDRIOD_INPUT_HOST_H diff --git a/services/inputflinger/host/main.cpp b/services/inputflinger/host/main.cpp new file mode 100644 index 0000000..0a517cc --- /dev/null +++ b/services/inputflinger/host/main.cpp @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2013 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include <binder/BinderService.h> +#include "InputFlinger.h" + +using namespace android; + +int main(int, char**) { + ProcessState::self()->setThreadPoolMaxThreadCount(4); + BinderService<InputFlinger>::publishAndJoinThreadPool(true); + return 0; +} diff --git a/services/inputflinger/tests/Android.mk b/services/inputflinger/tests/Android.mk index 0742a08..4c43392 100644 --- a/services/inputflinger/tests/Android.mk +++ b/services/inputflinger/tests/Android.mk @@ -10,7 +10,6 @@ test_src_files := \ shared_libraries := \ libcutils \ liblog \ - libandroidfw \ libutils \ libhardware \ libhardware_legacy \ @@ -24,7 +23,7 @@ c_includes := \ external/skia/include/core -module_tags := eng tests +module_tags := tests $(foreach file,$(test_src_files), \ $(eval include $(CLEAR_VARS)) \ diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp index 40f51b6..f34b810 100644 --- a/services/inputflinger/tests/InputReader_test.cpp +++ b/services/inputflinger/tests/InputReader_test.cpp @@ -777,6 +777,14 @@ private: virtual int32_t bumpGeneration() { return ++mGeneration; } + + virtual void getExternalStylusDevices(Vector<InputDeviceInfo>& outDevices) { + + } + + virtual void dispatchExternalStylusState(const StylusState&) { + + } }; diff --git a/services/sensorservice/SensorDevice.cpp b/services/sensorservice/SensorDevice.cpp index 80845a2..3bcbd58 100644 --- a/services/sensorservice/SensorDevice.cpp +++ b/services/sensorservice/SensorDevice.cpp @@ -85,6 +85,7 @@ void SensorDevice::dump(String8& result) Mutex::Autolock _l(mLock); for (size_t i=0 ; i<size_t(count) ; i++) { const Info& info = mActivationCount.valueFor(list[i].handle); + if (info.batchParams.isEmpty()) continue; result.appendFormat("handle=0x%08x, active-count=%zu, batch_period(ms)={ ", list[i].handle, info.batchParams.size()); for (size_t j = 0; j < info.batchParams.size(); j++) { @@ -147,8 +148,12 @@ status_t SensorDevice::activate(void* ident, int handle, int enabled) if (enabled) { ALOGD_IF(DEBUG_CONNECTIONS, "enable index=%zd", info.batchParams.indexOfKey(ident)); + if (isClientDisabledLocked(ident)) { + return INVALID_OPERATION; + } + if (info.batchParams.indexOfKey(ident) >= 0) { - if (info.batchParams.size() == 1) { + if (info.numActiveClients() == 1) { // This is the first connection, we need to activate the underlying h/w sensor. actuateHardware = true; } @@ -160,7 +165,7 @@ status_t SensorDevice::activate(void* ident, int handle, int enabled) ALOGD_IF(DEBUG_CONNECTIONS, "disable index=%zd", info.batchParams.indexOfKey(ident)); if (info.removeBatchParamsForIdent(ident) >= 0) { - if (info.batchParams.size() == 0) { + if (info.numActiveClients() == 0) { // This is the last connection, we need to de-activate the underlying h/w sensor. actuateHardware = true; } else { @@ -181,10 +186,15 @@ status_t SensorDevice::activate(void* ident, int handle, int enabled) } else { // sensor wasn't enabled for this ident } + + if (isClientDisabledLocked(ident)) { + return NO_ERROR; + } } if (actuateHardware) { - ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w activate handle=%d enabled=%d", handle, enabled); + ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w activate handle=%d enabled=%d", handle, + enabled); err = mSensorDevice->activate( reinterpret_cast<struct sensors_poll_device_t *> (mSensorDevice), handle, enabled); ALOGE_IF(err, "Error %s sensor %d (%s)", enabled ? "activating" : "disabling", handle, @@ -197,7 +207,7 @@ status_t SensorDevice::activate(void* ident, int handle, int enabled) } // On older devices which do not support batch, call setDelay(). - if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1 && info.batchParams.size() > 0) { + if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1 && info.numActiveClients() > 0) { ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w setDelay %d %" PRId64, handle, info.bestBatchParams.batchDelay); mSensorDevice->setDelay( @@ -279,6 +289,7 @@ status_t SensorDevice::setDelay(void* ident, int handle, int64_t samplingPeriodN samplingPeriodNs = MINIMUM_EVENTS_PERIOD; } Mutex::Autolock _l(mLock); + if (isClientDisabledLocked(ident)) return INVALID_OPERATION; Info& info( mActivationCount.editValueFor(handle) ); // If the underlying sensor is NOT in continuous mode, setDelay() should return an error. // Calling setDelay() in batch mode is an invalid operation. @@ -298,7 +309,6 @@ status_t SensorDevice::setDelay(void* ident, int handle, int64_t samplingPeriodN int SensorDevice::getHalDeviceVersion() const { if (!mSensorDevice) return -1; - return mSensorDevice->common.version; } @@ -306,12 +316,110 @@ status_t SensorDevice::flush(void* ident, int handle) { if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_1) { return INVALID_OPERATION; } + if (isClientDisabled(ident)) return INVALID_OPERATION; ALOGD_IF(DEBUG_CONNECTIONS, "\t>>> actuating h/w flush %d", handle); return mSensorDevice->flush(mSensorDevice, handle); } +bool SensorDevice::isClientDisabled(void* ident) { + Mutex::Autolock _l(mLock); + return isClientDisabledLocked(ident); +} + +bool SensorDevice::isClientDisabledLocked(void* ident) { + return mDisabledClients.indexOf(ident) >= 0; +} + +void SensorDevice::enableAllSensors() { + Mutex::Autolock _l(mLock); + mDisabledClients.clear(); + const int halVersion = getHalDeviceVersion(); + for (size_t i = 0; i< mActivationCount.size(); ++i) { + Info& info = mActivationCount.editValueAt(i); + if (info.batchParams.isEmpty()) continue; + info.selectBatchParams(); + const int sensor_handle = mActivationCount.keyAt(i); + ALOGD_IF(DEBUG_CONNECTIONS, "\t>> reenable actuating h/w sensor enable handle=%d ", + sensor_handle); + status_t err(NO_ERROR); + if (halVersion > SENSORS_DEVICE_API_VERSION_1_0) { + err = mSensorDevice->batch(mSensorDevice, sensor_handle, + info.bestBatchParams.flags, info.bestBatchParams.batchDelay, + info.bestBatchParams.batchTimeout); + ALOGE_IF(err, "Error calling batch on sensor %d (%s)", sensor_handle, strerror(-err)); + } + + if (err == NO_ERROR) { + err = mSensorDevice->activate( + reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice), + sensor_handle, 1); + ALOGE_IF(err, "Error activating sensor %d (%s)", sensor_handle, strerror(-err)); + } + + if (halVersion <= SENSORS_DEVICE_API_VERSION_1_0) { + err = mSensorDevice->setDelay( + reinterpret_cast<struct sensors_poll_device_t *>(mSensorDevice), + sensor_handle, info.bestBatchParams.batchDelay); + ALOGE_IF(err, "Error calling setDelay sensor %d (%s)", sensor_handle, strerror(-err)); + } + } +} + +void SensorDevice::disableAllSensors() { + Mutex::Autolock _l(mLock); + for (size_t i = 0; i< mActivationCount.size(); ++i) { + const Info& info = mActivationCount.valueAt(i); + // Check if this sensor has been activated previously and disable it. + if (info.batchParams.size() > 0) { + const int sensor_handle = mActivationCount.keyAt(i); + ALOGD_IF(DEBUG_CONNECTIONS, "\t>> actuating h/w sensor disable handle=%d ", + sensor_handle); + mSensorDevice->activate( + reinterpret_cast<struct sensors_poll_device_t *> (mSensorDevice), + sensor_handle, 0); + // Add all the connections that were registered for this sensor to the disabled + // clients list. + for (int j = 0; j < info.batchParams.size(); ++j) { + mDisabledClients.add(info.batchParams.keyAt(j)); + } + } + } +} + +status_t SensorDevice::injectSensorData(const sensors_event_t *injected_sensor_event, size_t count) { + ALOGD_IF(DEBUG_CONNECTIONS, + "sensor_event handle=%d ts=%lld data=%.2f, %.2f, %.2f %.2f %.2f %.2f", + injected_sensor_event->sensor, + injected_sensor_event->timestamp, injected_sensor_event->data[0], + injected_sensor_event->data[1], injected_sensor_event->data[2], + injected_sensor_event->data[3], injected_sensor_event->data[4], + injected_sensor_event->data[5]); + if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_4) { + return INVALID_OPERATION; + } + return mSensorDevice->inject_sensor_data(mSensorDevice, injected_sensor_event); +} + +status_t SensorDevice::setMode(uint32_t mode) { + if (getHalDeviceVersion() < SENSORS_DEVICE_API_VERSION_1_4) { + return INVALID_OPERATION; + } + return mSensorModule->set_operation_mode(mode); +} + // --------------------------------------------------------------------------- +int SensorDevice::Info::numActiveClients() { + SensorDevice& device(SensorDevice::getInstance()); + int num = 0; + for (size_t i = 0; i < batchParams.size(); ++i) { + if (!device.isClientDisabledLocked(batchParams.keyAt(i))) { + ++num; + } + } + return num; +} + status_t SensorDevice::Info::setBatchParamsForIdent(void* ident, int flags, int64_t samplingPeriodNs, int64_t maxBatchReportLatencyNs) { @@ -329,19 +437,16 @@ status_t SensorDevice::Info::setBatchParamsForIdent(void* ident, int flags, } void SensorDevice::Info::selectBatchParams() { - BatchParams bestParams(-1, -1, -1); - - if (batchParams.size() > 0) { - BatchParams params = batchParams.valueAt(0); - bestParams = params; - } + BatchParams bestParams(0, -1, -1); + SensorDevice& device(SensorDevice::getInstance()); - for (size_t i = 1; i < batchParams.size(); ++i) { + for (size_t i = 0; i < batchParams.size(); ++i) { + if (device.isClientDisabledLocked(batchParams.keyAt(i))) continue; BatchParams params = batchParams.valueAt(i); - if (params.batchDelay < bestParams.batchDelay) { + if (bestParams.batchDelay == -1 || params.batchDelay < bestParams.batchDelay) { bestParams.batchDelay = params.batchDelay; } - if (params.batchTimeout < bestParams.batchTimeout) { + if (bestParams.batchTimeout == -1 || params.batchTimeout < bestParams.batchTimeout) { bestParams.batchTimeout = params.batchTimeout; } } diff --git a/services/sensorservice/SensorDevice.h b/services/sensorservice/SensorDevice.h index 761b48c..4b3fe85 100644 --- a/services/sensorservice/SensorDevice.h +++ b/services/sensorservice/SensorDevice.h @@ -42,6 +42,7 @@ class SensorDevice : public Singleton<SensorDevice> { // Struct to store all the parameters(samplingPeriod, maxBatchReportLatency and flags) from // batch call. For continous mode clients, maxBatchReportLatency is set to zero. struct BatchParams { + // TODO: Get rid of flags parameter everywhere. int flags; nsecs_t batchDelay, batchTimeout; BatchParams() : flags(0), batchDelay(0), batchTimeout(0) {} @@ -65,7 +66,7 @@ class SensorDevice : public Singleton<SensorDevice> { // requested by the client. KeyedVector<void*, BatchParams> batchParams; - Info() : bestBatchParams(-1, -1, -1) {} + Info() : bestBatchParams(0, -1, -1) {} // Sets batch parameters for this ident. Returns error if this ident is not already present // in the KeyedVector above. status_t setBatchParamsForIdent(void* ident, int flags, int64_t samplingPeriodNs, @@ -75,10 +76,17 @@ class SensorDevice : public Singleton<SensorDevice> { // Removes batchParams for an ident and re-computes bestBatchParams. Returns the index of // the removed ident. If index >=0, ident is present and successfully removed. ssize_t removeBatchParamsForIdent(void* ident); + + int numActiveClients(); }; DefaultKeyedVector<int, Info> mActivationCount; + // Use this vector to determine which client is activated or deactivated. + SortedVector<void *> mDisabledClients; SensorDevice(); + + bool isClientDisabled(void* ident); + bool isClientDisabledLocked(void* ident); public: ssize_t getSensorList(sensor_t const** list); status_t initCheck() const; @@ -90,7 +98,11 @@ public: // Call batch with timeout zero instead of calling setDelay() for newer devices. status_t setDelay(void* ident, int handle, int64_t ns); status_t flush(void* ident, int handle); + status_t setMode(uint32_t mode); + void disableAllSensors(); + void enableAllSensors(); void autoDisable(void *ident, int handle); + status_t injectSensorData(const sensors_event_t *event, size_t count); void dump(String8& result); }; diff --git a/services/sensorservice/SensorService.cpp b/services/sensorservice/SensorService.cpp index a857366..c8dc6ec 100644 --- a/services/sensorservice/SensorService.cpp +++ b/services/sensorservice/SensorService.cpp @@ -64,6 +64,9 @@ namespace android { */ const char* SensorService::WAKE_LOCK_NAME = "SensorService"; +// Permissions. +static const String16 sDataInjectionPermission("android.permission.HARDWARE_TEST"); +static const String16 sDump("android.permission.DUMP"); SensorService::SensorService() : mInitCheck(NO_INIT), mSocketBufferSize(SOCKET_BUFFER_SIZE_NON_BATCHED), @@ -74,7 +77,6 @@ SensorService::SensorService() void SensorService::onFirstRef() { ALOGD("nuSensorService starting..."); - SensorDevice& dev(SensorDevice::getInstance()); if (dev.initCheck() == NO_ERROR) { @@ -190,6 +192,7 @@ void SensorService::onFirstRef() mSensorEventBuffer = new sensors_event_t[minBufferSize]; mSensorEventScratch = new sensors_event_t[minBufferSize]; mMapFlushEventsToConnections = new SensorEventConnection const * [minBufferSize]; + mCurrentOperatingMode = NORMAL; mAckReceiver = new SensorEventAckReceiver(this); mAckReceiver->run("SensorEventAckReceiver", PRIORITY_URGENT_DISPLAY); @@ -228,9 +231,7 @@ SensorService::~SensorService() delete mSensorMap.valueAt(i); } -static const String16 sDump("android.permission.DUMP"); - -status_t SensorService::dump(int fd, const Vector<String16>& /*args*/) +status_t SensorService::dump(int fd, const Vector<String16>& args) { String8 result; if (!PermissionCache::checkCallingPermission(sDump)) { @@ -238,6 +239,26 @@ status_t SensorService::dump(int fd, const Vector<String16>& /*args*/) "can't dump SensorService from pid=%d, uid=%d\n", IPCThreadState::self()->getCallingPid(), IPCThreadState::self()->getCallingUid()); + } else if (args.size() > 0) { + if (args.size() > 1) { + return INVALID_OPERATION; + } + Mutex::Autolock _l(mLock); + SensorDevice& dev(SensorDevice::getInstance()); + if (args[0] == String16("restrict") && mCurrentOperatingMode == NORMAL) { + mCurrentOperatingMode = RESTRICTED; + dev.disableAllSensors(); + // Clear all pending flush connections for all active sensors. If one of the active + // connections has called flush() and the underlying sensor has been disabled before a + // flush complete event is returned, we need to remove the connection from this queue. + for (size_t i=0 ; i< mActiveSensors.size(); ++i) { + mActiveSensors.valueAt(i)->clearAllPendingFlushConnections(); + } + } else if (args[0] == String16("enable") && mCurrentOperatingMode == RESTRICTED) { + mCurrentOperatingMode = NORMAL; + dev.enableAllSensors(); + } + return status_t(NO_ERROR); } else { Mutex::Autolock _l(mLock); result.append("Sensor List:\n"); @@ -341,6 +362,17 @@ status_t SensorService::dump(int fd, const Vector<String16>& /*args*/) result.appendFormat("Socket Buffer size = %d events\n", mSocketBufferSize/sizeof(sensors_event_t)); result.appendFormat("WakeLock Status: %s \n", mWakeLockAcquired ? "acquired" : "not held"); + result.appendFormat("Mode :"); + switch(mCurrentOperatingMode) { + case NORMAL: + result.appendFormat(" NORMAL\n"); + break; + case RESTRICTED: + result.appendFormat(" RESTRICTED\n"); + break; + case DATA_INJECTION: + result.appendFormat(" DATA_INJECTION\n"); + } result.appendFormat("%zd active connections\n", mActiveConnections.size()); for (size_t i=0 ; i < mActiveConnections.size() ; i++) { @@ -371,8 +403,9 @@ void SensorService::cleanupAutoDisabledSensorLocked(const sp<SensorEventConnecti sensor->autoDisable(connection.get(), handle); cleanupWithoutDisableLocked(connection, handle); } + } - } + } } bool SensorService::threadLoop() @@ -554,7 +587,6 @@ void SensorService::setWakeLockAcquiredLocked(bool acquire) { } } - bool SensorService::isWakeLockAcquired() { Mutex::Autolock _l(mLock); return mWakeLockAcquired; @@ -630,7 +662,6 @@ bool SensorService::isWakeUpSensorEvent(const sensors_event_t& event) const { return sensor != NULL && sensor->getSensor().isWakeUpSensor(); } - SensorService::SensorRecord * SensorService::getSensorRecord(int handle) { return mActiveSensors.valueFor(handle); } @@ -655,13 +686,76 @@ Vector<Sensor> SensorService::getSensorList() return accessibleSensorList; } -sp<ISensorEventConnection> SensorService::createSensorEventConnection() -{ +sp<ISensorEventConnection> SensorService::createSensorEventConnection(const String8& packageName, + int requestedMode) { + // Only 2 modes supported for a SensorEventConnection ... NORMAL and DATA_INJECTION. + if (requestedMode != NORMAL && requestedMode != DATA_INJECTION) { + return NULL; + } + // DATA_INJECTION mode needs to have the required permissions set. + if (requestedMode == DATA_INJECTION && !hasDataInjectionPermissions()) { + return NULL; + } + + Mutex::Autolock _l(mLock); uid_t uid = IPCThreadState::self()->getCallingUid(); - sp<SensorEventConnection> result(new SensorEventConnection(this, uid)); + sp<SensorEventConnection> result(new SensorEventConnection(this, uid, packageName, + requestedMode == DATA_INJECTION)); + if (requestedMode == DATA_INJECTION) { + if (mActiveConnections.indexOf(result) < 0) { + mActiveConnections.add(result); + } + // Add the associated file descriptor to the Looper for polling whenever there is data to + // be injected. + result->updateLooperRegistration(mLooper); + } return result; } +status_t SensorService::enableDataInjection(int requestedMode) { + if (!hasDataInjectionPermissions()) { + return INVALID_OPERATION; + } + Mutex::Autolock _l(mLock); + ALOGD_IF(DEBUG_CONNECTIONS, "SensorService::enableDataInjection %d", requestedMode); + SensorDevice& dev(SensorDevice::getInstance()); + status_t err(NO_ERROR); + if (requestedMode == DATA_INJECTION) { + if (mCurrentOperatingMode == NORMAL) { + dev.disableAllSensors(); + err = dev.setMode(requestedMode); + if (err == NO_ERROR) { + mCurrentOperatingMode = DATA_INJECTION; + } else { + // Re-enable sensors. + dev.enableAllSensors(); + } + } else if (mCurrentOperatingMode == DATA_INJECTION) { + // Already in DATA_INJECTION mode. Treat this as a no_op. + return NO_ERROR; + } else { + // Transition to data injection mode supported only from NORMAL mode. + return INVALID_OPERATION; + } + } else if (requestedMode == NORMAL && mCurrentOperatingMode != NORMAL) { + err = resetToNormalModeLocked(); + } + return err; +} + +status_t SensorService::resetToNormalMode() { + Mutex::Autolock _l(mLock); + return resetToNormalModeLocked(); +} + +status_t SensorService::resetToNormalModeLocked() { + SensorDevice& dev(SensorDevice::getInstance()); + dev.enableAllSensors(); + status_t err = dev.setMode(NORMAL); + mCurrentOperatingMode = NORMAL; + return err; +} + void SensorService::cleanupConnection(SensorEventConnection* c) { Mutex::Autolock _l(mLock); @@ -708,7 +802,7 @@ Sensor SensorService::getSensorFromHandle(int handle) const { } status_t SensorService::enable(const sp<SensorEventConnection>& connection, - int handle, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags) + int handle, nsecs_t samplingPeriodNs, nsecs_t maxBatchReportLatencyNs, int reservedFlags) { if (mInitCheck != NO_ERROR) return mInitCheck; @@ -723,6 +817,10 @@ status_t SensorService::enable(const sp<SensorEventConnection>& connection, } Mutex::Autolock _l(mLock); + if (mCurrentOperatingMode == RESTRICTED && !isWhiteListedPackage(connection->getPackageName())) { + return INVALID_OPERATION; + } + SensorRecord* rec = mActiveSensors.valueFor(handle); if (rec == 0) { rec = new SensorRecord(connection); @@ -773,7 +871,7 @@ status_t SensorService::enable(const sp<SensorEventConnection>& connection, "rate=%" PRId64 " timeout== %" PRId64"", handle, reservedFlags, samplingPeriodNs, maxBatchReportLatencyNs); - status_t err = sensor->batch(connection.get(), handle, reservedFlags, samplingPeriodNs, + status_t err = sensor->batch(connection.get(), handle, 0, samplingPeriodNs, maxBatchReportLatencyNs); // Call flush() before calling activate() on the sensor. Wait for a first flush complete @@ -926,6 +1024,15 @@ bool SensorService::verifyCanAccessSensor(const Sensor& sensor, const char* oper } } +bool SensorService::hasDataInjectionPermissions() { + if (!PermissionCache::checkCallingPermission(sDataInjectionPermission)) { + ALOGE("Permission Denial trying to activate data injection without" + " the required permission"); + return false; + } + return true; +} + void SensorService::checkWakeLockState() { Mutex::Autolock _l(mLock); checkWakeLockStateLocked(); @@ -969,6 +1076,11 @@ void SensorService::populateActiveConnections( } } +bool SensorService::isWhiteListedPackage(const String8& packageName) { + // TODO: Come up with a list of packages. + return (packageName.find(".cts.") != -1); +} + // --------------------------------------------------------------------------- SensorService::SensorRecord::SensorRecord( const sp<SensorEventConnection>& connection) @@ -1025,12 +1137,17 @@ SensorService::SensorRecord::getFirstPendingFlushConnection() { return NULL; } +void SensorService::SensorRecord::clearAllPendingFlushConnections() { + mPendingFlushConnections.clear(); +} + // --------------------------------------------------------------------------- SensorService::SensorEventConnection::SensorEventConnection( - const sp<SensorService>& service, uid_t uid) + const sp<SensorService>& service, uid_t uid, String8 packageName, bool isDataInjectionMode) : mService(service), mUid(uid), mWakeLockRefCount(0), mHasLooperCallbacks(false), - mDead(false), mEventCache(NULL), mCacheSize(0), mMaxCacheSize(0) { + mDead(false), mEventCache(NULL), mCacheSize(0), mMaxCacheSize(0), mPackageName(packageName), + mDataInjectionMode(isDataInjectionMode) { mChannel = new BitTube(mService->mSocketBufferSize); #if DEBUG_CONNECTIONS mEventsReceived = mEventsSentFromCache = mEventsSent = 0; @@ -1062,8 +1179,9 @@ void SensorService::SensorEventConnection::resetWakeLockRefCount() { void SensorService::SensorEventConnection::dump(String8& result) { Mutex::Autolock _l(mConnectionLock); - result.appendFormat("\t WakeLockRefCount %d | uid %d | cache size %d | max cache size %d\n", - mWakeLockRefCount, mUid, mCacheSize, mMaxCacheSize); + result.appendFormat("Operating Mode: %s\n", mDataInjectionMode ? "DATA_INJECTION" : "NORMAL"); + result.appendFormat("\t%s | WakeLockRefCount %d | uid %d | cache size %d | max cache size %d\n", + mPackageName.string(), mWakeLockRefCount, mUid, mCacheSize, mMaxCacheSize); for (size_t i = 0; i < mSensorInfo.size(); ++i) { const FlushInfo& flushInfo = mSensorInfo.valueAt(i); result.appendFormat("\t %s 0x%08x | status: %s | pending flush events %d \n", @@ -1126,6 +1244,10 @@ bool SensorService::SensorEventConnection::hasOneShotSensors() const { return false; } +String8 SensorService::SensorEventConnection::getPackageName() const { + return mPackageName; +} + void SensorService::SensorEventConnection::setFirstFlushPending(int32_t handle, bool value) { Mutex::Autolock _l(mConnectionLock); @@ -1143,7 +1265,8 @@ void SensorService::SensorEventConnection::updateLooperRegistration(const sp<Loo void SensorService::SensorEventConnection::updateLooperRegistrationLocked( const sp<Looper>& looper) { - bool isConnectionActive = mSensorInfo.size() > 0; + bool isConnectionActive = (mSensorInfo.size() > 0 && !mDataInjectionMode) || + mDataInjectionMode; // If all sensors are unregistered OR Looper has encountered an error, we // can remove the Fd from the Looper if it has been previously added. if (!isConnectionActive || mDead) { @@ -1157,6 +1280,7 @@ void SensorService::SensorEventConnection::updateLooperRegistrationLocked( int looper_flags = 0; if (mCacheSize > 0) looper_flags |= ALOOPER_EVENT_OUTPUT; + if (mDataInjectionMode) looper_flags |= ALOOPER_EVENT_INPUT; for (size_t i = 0; i < mSensorInfo.size(); ++i) { const int handle = mSensorInfo.keyAt(i); if (mService->getSensorFromHandle(handle).isWakeUpSensor()) { @@ -1523,26 +1647,55 @@ int SensorService::SensorEventConnection::handleEvent(int fd, int events, void* updateLooperRegistrationLocked(mService->getLooper()); } mService->checkWakeLockState(); + if (mDataInjectionMode) { + // If the Looper has encountered some error in data injection mode, reset SensorService + // back to normal mode. + mService->resetToNormalMode(); + mDataInjectionMode = false; + } return 1; } if (events & ALOOPER_EVENT_INPUT) { - uint32_t numAcks = 0; - ssize_t ret = ::recv(fd, &numAcks, sizeof(numAcks), MSG_DONTWAIT); + unsigned char buf[sizeof(sensors_event_t)]; + ssize_t numBytesRead = ::recv(fd, buf, sizeof(buf), MSG_DONTWAIT); { Mutex::Autolock _l(mConnectionLock); - // Sanity check to ensure there are no read errors in recv, numAcks is always - // within the range and not zero. If any of the above don't hold reset mWakeLockRefCount - // to zero. - if (ret != sizeof(numAcks) || numAcks > mWakeLockRefCount || numAcks == 0) { - ALOGE("Looper read error ret=%d numAcks=%d", ret, numAcks); - mWakeLockRefCount = 0; - } else { - mWakeLockRefCount -= numAcks; - } + if (numBytesRead == sizeof(sensors_event_t)) { + if (!mDataInjectionMode) { + ALOGE("Data injected in normal mode, dropping event" + "package=%s uid=%d", mPackageName.string(), mUid); + // Unregister call backs. + return 0; + } + SensorDevice& dev(SensorDevice::getInstance()); + sensors_event_t sensor_event; + memset(&sensor_event, 0, sizeof(sensor_event)); + memcpy(&sensor_event, buf, sizeof(sensors_event_t)); + Sensor sensor = mService->getSensorFromHandle(sensor_event.sensor); + sensor_event.type = sensor.getType(); + dev.injectSensorData(&sensor_event, 1); +#if DEBUG_CONNECTIONS + ++mEventsReceived; +#endif + } else if (numBytesRead == sizeof(uint32_t)) { + uint32_t numAcks = 0; + memcpy(&numAcks, buf, sizeof(numBytesRead)); + // Sanity check to ensure there are no read errors in recv, numAcks is always + // within the range and not zero. If any of the above don't hold reset + // mWakeLockRefCount to zero. + if (numAcks > 0 && numAcks < mWakeLockRefCount) { + mWakeLockRefCount -= numAcks; + } else { + mWakeLockRefCount = 0; + } #if DEBUG_CONNECTIONS - mTotalAcksReceived += numAcks; + mTotalAcksReceived += numAcks; #endif + } else { + // Read error, reset wakelock refcount. + mWakeLockRefCount = 0; + } } // Check if wakelock can be released by sensorservice. mConnectionLock needs to be released // here as checkWakeLockState() will need it. diff --git a/services/sensorservice/SensorService.h b/services/sensorservice/SensorService.h index e9ca3a5..4d34471 100644 --- a/services/sensorservice/SensorService.h +++ b/services/sensorservice/SensorService.h @@ -27,6 +27,7 @@ #include <utils/AndroidThreads.h> #include <utils/RefBase.h> #include <utils/Looper.h> +#include <utils/String8.h> #include <binder/BinderService.h> @@ -65,6 +66,39 @@ class SensorService : { friend class BinderService<SensorService>; + enum Mode { + // The regular operating mode where any application can register/unregister/call flush on + // sensors. + NORMAL = 0, + // This mode is only used for testing purposes. Not all HALs support this mode. In this + // mode, the HAL ignores the sensor data provided by physical sensors and accepts the data + // that is injected from the SensorService as if it were the real sensor data. This mode + // is primarily used for testing various algorithms like vendor provided SensorFusion, + // Step Counter and Step Detector etc. Typically in this mode, there will be a client + // (a SensorEventConnection) which will be injecting sensor data into the HAL. Normal apps + // can unregister and register for any sensor that supports injection. Registering to sensors + // that do not support injection will give an error. + // TODO(aakella) : Allow exactly one client to inject sensor data at a time. + DATA_INJECTION = 1, + // This mode is used only for testing sensors. Each sensor can be tested in isolation with + // the required sampling_rate and maxReportLatency parameters without having to think about + // the data rates requested by other applications. End user devices are always expected to be + // in NORMAL mode. When this mode is first activated, all active sensors from all connections + // are disabled. Calling flush() will return an error. In this mode, only the requests from + // selected apps whose package names are whitelisted are allowed (typically CTS apps). Only + // these apps can register/unregister/call flush() on sensors. If SensorService switches to + // NORMAL mode again, all sensors that were previously registered to are activated with the + // corresponding paramaters if the application hasn't unregistered for sensors in the mean + // time. + // NOTE: Non whitelisted app whose sensors were previously deactivated may still receive + // events if a whitelisted app requests data from the same sensor. + RESTRICTED = 2 + + // State Transitions supported. + // RESTRICTED <--- NORMAL ---> DATA_INJECTION + // ---> <--- + }; + static const char* WAKE_LOCK_NAME; static char const* getServiceName() ANDROID_API { return "sensorservice"; } @@ -78,7 +112,9 @@ class SensorService : // ISensorServer interface virtual Vector<Sensor> getSensorList(); - virtual sp<ISensorEventConnection> createSensorEventConnection(); + virtual sp<ISensorEventConnection> createSensorEventConnection(const String8& packageName, + int requestedMode); + virtual status_t enableDataInjection(int enable); virtual status_t dump(int fd, const Vector<String16>& args); class SensorEventConnection : public BnSensorEventConnection, public LooperCallback { @@ -133,7 +169,6 @@ class SensorService : // connection FD may be added to the Looper. The flags to set are determined by the internal // state of the connection. FDs are added to the looper when wake-up sensors are registered // (to poll for acknowledgements) and when write fails on the socket when there are too many - // events (to poll when the FD is available for writing). FDs are removed when there is an // error and the other end hangs up or when this client unregisters for this connection. void updateLooperRegistration(const sp<Looper>& looper); void updateLooperRegistrationLocked(const sp<Looper>& looper); @@ -156,6 +191,8 @@ class SensorService : // mWakeLockRefCount is reset to zero. needsWakeLock method will always return false, if // this flag is set. bool mDead; + + bool mDataInjectionMode; struct FlushInfo { // The number of flush complete events dropped for this sensor is stored here. // They are sent separately before the next batch of events. @@ -169,14 +206,15 @@ class SensorService : KeyedVector<int, FlushInfo> mSensorInfo; sensors_event_t *mEventCache; int mCacheSize, mMaxCacheSize; - + String8 mPackageName; #if DEBUG_CONNECTIONS int mEventsReceived, mEventsSent, mEventsSentFromCache; int mTotalAcksNeeded, mTotalAcksReceived; #endif public: - SensorEventConnection(const sp<SensorService>& service, uid_t uid); + SensorEventConnection(const sp<SensorService>& service, uid_t uid, String8 packageName, + bool isDataInjectionMode); status_t sendEvents(sensors_event_t const* buffer, size_t count, sensors_event_t* scratch, @@ -190,6 +228,7 @@ class SensorService : void dump(String8& result); bool needsWakeLock(); void resetWakeLockRefCount(); + String8 getPackageName() const; uid_t getUid() const { return mUid; } }; @@ -208,6 +247,7 @@ class SensorService : void addPendingFlushConnection(const sp<SensorEventConnection>& connection); void removeFirstPendingFlushConnection(); SensorEventConnection * getFirstPendingFlushConnection(); + void clearAllPendingFlushConnections(); }; class SensorEventAckReceiver : public Thread { @@ -233,6 +273,7 @@ class SensorService : sensors_event_t const* buffer, const int count); static bool canAccessSensor(const Sensor& sensor); static bool verifyCanAccessSensor(const Sensor& sensor, const char* operation); + static bool hasDataInjectionPermissions(); // SensorService acquires a partial wakelock for delivering events from wake up sensors. This // method checks whether all the events from these wake up sensors have been delivered to the // corresponding applications, if yes the wakelock is released. @@ -261,6 +302,15 @@ class SensorService : // to the output vector. void populateActiveConnections(SortedVector< sp<SensorEventConnection> >* activeConnections); + // If SensorService is operating in RESTRICTED mode, only select whitelisted packages are + // allowed to register for or call flush on sensors. Typically only cts test packages are + // allowed. + bool isWhiteListedPackage(const String8& packageName); + + // Reset the state of SensorService to NORMAL mode. + status_t resetToNormalMode(); + status_t resetToNormalModeLocked(); + // constants Vector<Sensor> mSensorList; Vector<Sensor> mUserSensorListDebug; @@ -282,6 +332,7 @@ class SensorService : bool mWakeLockAcquired; sensors_event_t *mSensorEventBuffer, *mSensorEventScratch; SensorEventConnection const **mMapFlushEventsToConnections; + Mode mCurrentOperatingMode; // The size of this vector is constant, only the items are mutable KeyedVector<int32_t, sensors_event_t> mLastEventSeen; diff --git a/services/surfaceflinger/Client.cpp b/services/surfaceflinger/Client.cpp index f7d32d0..49389e0 100644 --- a/services/surfaceflinger/Client.cpp +++ b/services/surfaceflinger/Client.cpp @@ -93,7 +93,7 @@ status_t Client::onTransact( const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); const int self_pid = getpid(); - if (CC_UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != 0)) { + if (CC_UNLIKELY(pid != self_pid && uid != AID_GRAPHICS && uid != AID_SYSTEM && uid != 0)) { // we're called from a different process, do the real check if (!PermissionCache::checkCallingPermission(sAccessSurfaceFlinger)) { diff --git a/services/surfaceflinger/DdmConnection.cpp b/services/surfaceflinger/DdmConnection.cpp index a000a84..659c2c8 100644 --- a/services/surfaceflinger/DdmConnection.cpp +++ b/services/surfaceflinger/DdmConnection.cpp @@ -66,7 +66,7 @@ void DdmConnection::start(const char* name) { jint (*registerNatives)(JNIEnv* env, jclass clazz); registerNatives = reinterpret_cast<decltype(registerNatives)>( dlsym(libandroid_runtime_dso, - "Java_com_android_internal_util_WithFramework_registerNatives")); + "Java_com_android_internal_util_WithFramework_registerNatives")); ALOGE_IF(!registerNatives, "DdmConnection: %s", dlerror()); if (!JNI_CreateJavaVM || !registerNatives) { diff --git a/services/surfaceflinger/SurfaceFlinger.cpp b/services/surfaceflinger/SurfaceFlinger.cpp index df4ac2e..1419557 100644 --- a/services/surfaceflinger/SurfaceFlinger.cpp +++ b/services/surfaceflinger/SurfaceFlinger.cpp @@ -149,7 +149,11 @@ SurfaceFlinger::SurfaceFlinger() mPrimaryHWVsyncEnabled(false), mHWVsyncAvailable(false), mDaltonize(false), - mHasColorMatrix(false) + mHasColorMatrix(false), + mHasPoweredOff(false), + mFrameBuckets(), + mTotalTime(0), + mLastSwapTime(0) { ALOGI("SurfaceFlinger is starting"); @@ -997,8 +1001,8 @@ void SurfaceFlinger::postComposition() } } + const sp<const DisplayDevice> hw(getDefaultDisplayDevice()); if (kIgnorePresentFences) { - const sp<const DisplayDevice> hw(getDefaultDisplayDevice()); if (hw->isDisplayOn()) { enableHardwareVsync(); } @@ -1017,6 +1021,26 @@ void SurfaceFlinger::postComposition() } mAnimFrameTracker.advanceFrame(); } + + if (hw->getPowerMode() == HWC_POWER_MODE_OFF) { + return; + } + + nsecs_t currentTime = systemTime(); + if (mHasPoweredOff) { + mHasPoweredOff = false; + } else { + nsecs_t period = mPrimaryDispSync.getPeriod(); + nsecs_t elapsedTime = currentTime - mLastSwapTime; + size_t numPeriods = static_cast<size_t>(elapsedTime / period); + if (numPeriods < NUM_BUCKETS - 1) { + mFrameBuckets[numPeriods] += elapsedTime; + } else { + mFrameBuckets[NUM_BUCKETS - 1] += elapsedTime; + } + mTotalTime += elapsedTime; + } + mLastSwapTime = currentTime; } void SurfaceFlinger::rebuildLayerStacks() { @@ -2398,6 +2422,7 @@ void SurfaceFlinger::setPowerModeInternal(const sp<DisplayDevice>& hw, } mVisibleRegionsDirty = true; + mHasPoweredOff = true; repaintEverything(); } else if (mode == HWC_POWER_MODE_OFF) { if (type == DisplayDevice::DISPLAY_PRIMARY) { @@ -2498,6 +2523,13 @@ status_t SurfaceFlinger::dump(int fd, const Vector<String16>& args) mPrimaryDispSync.dump(result); dumpAll = false; } + + if ((index < numArgs) && + (args[index] == String16("--static-screen"))) { + index++; + dumpStaticScreenStats(result); + dumpAll = false; + } } if (dumpAll) { @@ -2601,6 +2633,23 @@ void SurfaceFlinger::logFrameStats() { result.append(config); } +void SurfaceFlinger::dumpStaticScreenStats(String8& result) const +{ + result.appendFormat("Static screen stats:\n"); + for (size_t b = 0; b < NUM_BUCKETS - 1; ++b) { + float bucketTimeSec = mFrameBuckets[b] / 1e9; + float percent = 100.0f * + static_cast<float>(mFrameBuckets[b]) / mTotalTime; + result.appendFormat(" < %zd frames: %.3f s (%.1f%%)\n", + b + 1, bucketTimeSec, percent); + } + float bucketTimeSec = mFrameBuckets[NUM_BUCKETS - 1] / 1e9; + float percent = 100.0f * + static_cast<float>(mFrameBuckets[NUM_BUCKETS - 1]) / mTotalTime; + result.appendFormat(" %zd+ frames: %.3f s (%.1f%%)\n", + NUM_BUCKETS - 1, bucketTimeSec, percent); +} + void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index, String8& result) const { @@ -2647,6 +2696,11 @@ void SurfaceFlinger::dumpAllLocked(const Vector<String16>& args, size_t& index, mHwc->getRefreshPeriod(HWC_DISPLAY_PRIMARY)); result.append("\n"); + // Dump static screen stats + result.append("\n"); + dumpStaticScreenStats(result); + result.append("\n"); + /* * Dump the visible layer list */ @@ -2794,7 +2848,7 @@ status_t SurfaceFlinger::onTransact( IPCThreadState* ipc = IPCThreadState::self(); const int pid = ipc->getCallingPid(); const int uid = ipc->getCallingUid(); - if ((uid != AID_GRAPHICS) && + if ((uid != AID_GRAPHICS && uid != AID_SYSTEM) && !PermissionCache::checkPermission(sAccessSurfaceFlinger, pid, uid)) { ALOGE("Permission Denial: " "can't access SurfaceFlinger pid=%d, uid=%d", pid, uid); diff --git a/services/surfaceflinger/SurfaceFlinger.h b/services/surfaceflinger/SurfaceFlinger.h index a06d1be..d2654d4 100644 --- a/services/surfaceflinger/SurfaceFlinger.h +++ b/services/surfaceflinger/SurfaceFlinger.h @@ -416,6 +416,8 @@ private: void logFrameStats(); + void dumpStaticScreenStats(String8& result) const; + /* ------------------------------------------------------------------------ * Attributes */ @@ -494,6 +496,13 @@ private: mat4 mColorMatrix; bool mHasColorMatrix; + + // Static screen stats + bool mHasPoweredOff; + static const size_t NUM_BUCKETS = 8; // < 1-7, 7+ + nsecs_t mFrameBuckets[NUM_BUCKETS]; + nsecs_t mTotalTime; + nsecs_t mLastSwapTime; }; }; // namespace android |