Merge "Revert "Revert "Remove GLTrace support"""
diff --git a/cmds/cmd/Android.mk b/cmds/cmd/Android.mk
new file mode 100644
index 0000000..ac2f4c0
--- /dev/null
+++ b/cmds/cmd/Android.mk
@@ -0,0 +1,20 @@
+LOCAL_PATH:= $(call my-dir)
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES:= \
+ cmd.cpp
+
+LOCAL_SHARED_LIBRARIES := \
+ libutils \
+ liblog \
+ libbinder
+
+
+ifeq ($(TARGET_OS),linux)
+ LOCAL_CFLAGS += -DXP_UNIX
+ #LOCAL_SHARED_LIBRARIES += librt
+endif
+
+LOCAL_MODULE:= cmd
+
+include $(BUILD_EXECUTABLE)
diff --git a/cmds/cmd/MODULE_LICENSE_APACHE2 b/cmds/cmd/MODULE_LICENSE_APACHE2
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/cmds/cmd/MODULE_LICENSE_APACHE2
diff --git a/cmds/cmd/NOTICE b/cmds/cmd/NOTICE
new file mode 100644
index 0000000..c5b1efa
--- /dev/null
+++ b/cmds/cmd/NOTICE
@@ -0,0 +1,190 @@
+
+ Copyright (c) 2005-2008, 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.
+
+ 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.
+
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
diff --git a/cmds/cmd/cmd.cpp b/cmds/cmd/cmd.cpp
new file mode 100644
index 0000000..ed740d3
--- /dev/null
+++ b/cmds/cmd/cmd.cpp
@@ -0,0 +1,96 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "cmd"
+
+#include <utils/Log.h>
+#include <binder/Parcel.h>
+#include <binder/ProcessState.h>
+#include <binder/IResultReceiver.h>
+#include <binder/IServiceManager.h>
+#include <binder/TextOutput.h>
+#include <utils/Vector.h>
+
+#include <getopt.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/time.h>
+
+using namespace android;
+
+static int sort_func(const String16* lhs, const String16* rhs)
+{
+ return lhs->compare(*rhs);
+}
+
+class MyResultReceiver : public BnResultReceiver
+{
+public:
+ virtual void send(int32_t /*resultCode*/) {
+ }
+};
+
+int main(int argc, char* const argv[])
+{
+ signal(SIGPIPE, SIG_IGN);
+ sp<ProcessState> proc = ProcessState::self();
+ proc->startThreadPool();
+
+ sp<IServiceManager> sm = defaultServiceManager();
+ fflush(stdout);
+ if (sm == NULL) {
+ ALOGE("Unable to get default service manager!");
+ aerr << "cmd: Unable to get default service manager!" << endl;
+ return 20;
+ }
+
+ if (argc == 1) {
+ aout << "cmd: no service specified; use -l to list all services" << endl;
+ return 20;
+ }
+
+ if ((argc == 2) && (strcmp(argv[1], "-l") == 0)) {
+ Vector<String16> services = sm->listServices();
+ services.sort(sort_func);
+ aout << "Currently running services:" << endl;
+
+ for (size_t i=0; i<services.size(); i++) {
+ sp<IBinder> service = sm->checkService(services[i]);
+ if (service != NULL) {
+ aout << " " << services[i] << endl;
+ }
+ }
+ return 0;
+ }
+
+ Vector<String16> args;
+ for (int i=2; i<argc; i++) {
+ args.add(String16(argv[i]));
+ }
+ String16 cmd = String16(argv[1]);
+ sp<IBinder> service = sm->checkService(cmd);
+ if (service == NULL) {
+ aerr << "Can't find service: " << argv[1] << endl;
+ return 20;
+ }
+
+ // TODO: block until a result is returned to MyResultReceiver.
+ IBinder::shellCommand(service, STDIN_FILENO, STDOUT_FILENO, STDERR_FILENO, args,
+ new MyResultReceiver());
+ return 0;
+}
diff --git a/cmds/dumpstate/dumpstate.c b/cmds/dumpstate/dumpstate.c
index 59c1d12..1da7308 100644
--- a/cmds/dumpstate/dumpstate.c
+++ b/cmds/dumpstate/dumpstate.c
@@ -300,7 +300,7 @@
dump_files("UPTIME MMC PERF", mmcblk0, skip_not_stat, dump_stat_from_fd);
dump_file("MEMORY INFO", "/proc/meminfo");
run_command("CPU INFO", 10, "top", "-n", "1", "-d", "1", "-m", "30", "-t", NULL);
- run_command("PROCRANK", 20, "procrank", NULL);
+ run_command("PROCRANK", 20, SU_PATH, "root", "procrank", NULL);
dump_file("VIRTUAL MEMORY STATS", "/proc/vmstat");
dump_file("VMALLOC INFO", "/proc/vmallocinfo");
dump_file("SLAB INFO", "/proc/slabinfo");
@@ -337,22 +337,32 @@
if (timeout < 20000) {
timeout = 20000;
}
- run_command("SYSTEM LOG", timeout / 1000, "logcat", "-v", "threadtime", "-d", "*:v", NULL);
+ run_command("SYSTEM LOG", timeout / 1000, "logcat", "-v", "threadtime",
+ "-v", "printable",
+ "-d",
+ "*:v", NULL);
timeout = logcat_timeout("events");
if (timeout < 20000) {
timeout = 20000;
}
- run_command("EVENT LOG", timeout / 1000, "logcat", "-b", "events", "-v", "threadtime", "-d", "*:v", NULL);
+ run_command("EVENT LOG", timeout / 1000, "logcat", "-b", "events",
+ "-v", "threadtime",
+ "-v", "printable",
+ "-d",
+ "*:v", NULL);
timeout = logcat_timeout("radio");
if (timeout < 20000) {
timeout = 20000;
}
- run_command("RADIO LOG", timeout / 1000, "logcat", "-b", "radio", "-v", "threadtime", "-d", "*:v", NULL);
+ run_command("RADIO LOG", timeout / 1000, "logcat", "-b", "radio",
+ "-v", "threadtime",
+ "-v", "printable",
+ "-d",
+ "*:v", NULL);
run_command("LOG STATISTICS", 10, "logcat", "-b", "all", "-S", NULL);
- // raft disabled as per http://b/24159112
- // run_command("RAFT LOGS", 300, SU_PATH, "root", "logcompressor", "-r", RAFT_DIR, NULL);
+ run_command("RAFT LOGS", 300, SU_PATH, "root", "logcompressor", "-r", RAFT_DIR, NULL);
/* show the traces we collected in main(), if that was done */
if (dump_traces_path != NULL) {
@@ -420,8 +430,12 @@
}
/* kernels must set CONFIG_PSTORE_PMSG, slice up pstore with device tree */
- run_command("LAST LOGCAT", 10, "logcat", "-L", "-v", "threadtime",
- "-b", "all", "-d", "*:v", NULL);
+ run_command("LAST LOGCAT", 10, "logcat", "-L",
+ "-b", "all",
+ "-v", "threadtime",
+ "-v", "printable",
+ "-d",
+ "*:v", NULL);
/* The following have a tendency to get wedged when wifi drivers/fw goes belly-up. */
diff --git a/cmds/servicemanager/service_manager.c b/cmds/servicemanager/service_manager.c
index 7fa9a39..8596f96 100644
--- a/cmds/servicemanager/service_manager.c
+++ b/cmds/servicemanager/service_manager.c
@@ -23,6 +23,12 @@
#include <cutils/log.h>
#endif
+struct audit_data {
+ pid_t pid;
+ uid_t uid;
+ const char *name;
+};
+
const char *str8(const uint16_t *x, size_t x_len)
{
static char buf[128];
@@ -56,34 +62,39 @@
static char *service_manager_context;
static struct selabel_handle* sehandle;
-static bool check_mac_perms(pid_t spid, const char *tctx, const char *perm, const char *name)
+static bool check_mac_perms(pid_t spid, uid_t uid, const char *tctx, const char *perm, const char *name)
{
char *sctx = NULL;
const char *class = "service_manager";
bool allowed;
+ struct audit_data ad;
if (getpidcon(spid, &sctx) < 0) {
ALOGE("SELinux: getpidcon(pid=%d) failed to retrieve pid context.\n", spid);
return false;
}
- int result = selinux_check_access(sctx, tctx, class, perm, (void *) name);
+ ad.pid = spid;
+ ad.uid = uid;
+ ad.name = name;
+
+ int result = selinux_check_access(sctx, tctx, class, perm, (void *) &ad);
allowed = (result == 0);
freecon(sctx);
return allowed;
}
-static bool check_mac_perms_from_getcon(pid_t spid, const char *perm)
+static bool check_mac_perms_from_getcon(pid_t spid, uid_t uid, const char *perm)
{
if (selinux_enabled <= 0) {
return true;
}
- return check_mac_perms(spid, service_manager_context, perm, NULL);
+ return check_mac_perms(spid, uid, service_manager_context, perm, NULL);
}
-static bool check_mac_perms_from_lookup(pid_t spid, const char *perm, const char *name)
+static bool check_mac_perms_from_lookup(pid_t spid, uid_t uid, const char *perm, const char *name)
{
bool allowed;
char *tctx = NULL;
@@ -102,27 +113,27 @@
return false;
}
- allowed = check_mac_perms(spid, tctx, perm, name);
+ allowed = check_mac_perms(spid, uid, tctx, perm, name);
freecon(tctx);
return allowed;
}
-static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid)
+static int svc_can_register(const uint16_t *name, size_t name_len, pid_t spid, uid_t uid)
{
const char *perm = "add";
- return check_mac_perms_from_lookup(spid, perm, str8(name, name_len)) ? 1 : 0;
+ return check_mac_perms_from_lookup(spid, uid, perm, str8(name, name_len)) ? 1 : 0;
}
-static int svc_can_list(pid_t spid)
+static int svc_can_list(pid_t spid, uid_t uid)
{
const char *perm = "list";
- return check_mac_perms_from_getcon(spid, perm) ? 1 : 0;
+ return check_mac_perms_from_getcon(spid, uid, perm) ? 1 : 0;
}
-static int svc_can_find(const uint16_t *name, size_t name_len, pid_t spid)
+static int svc_can_find(const uint16_t *name, size_t name_len, pid_t spid, uid_t uid)
{
const char *perm = "find";
- return check_mac_perms_from_lookup(spid, perm, str8(name, name_len)) ? 1 : 0;
+ return check_mac_perms_from_lookup(spid, uid, perm, str8(name, name_len)) ? 1 : 0;
}
struct svcinfo
@@ -184,7 +195,7 @@
}
}
- if (!svc_can_find(s, len, spid)) {
+ if (!svc_can_find(s, len, spid, uid)) {
return 0;
}
@@ -204,7 +215,7 @@
if (!handle || (len == 0) || (len > 127))
return -1;
- if (!svc_can_register(s, len, spid)) {
+ if (!svc_can_register(s, len, spid, uid)) {
ALOGE("add_service('%s',%x) uid=%d - PERMISSION DENIED\n",
str8(s, len), handle, uid);
return -1;
@@ -314,7 +325,7 @@
case SVC_MGR_LIST_SERVICES: {
uint32_t n = bio_get_uint32(msg);
- if (!svc_can_list(txn->sender_pid)) {
+ if (!svc_can_list(txn->sender_pid, txn->sender_euid)) {
ALOGE("list_service() uid=%d - PERMISSION DENIED\n",
txn->sender_euid);
return -1;
@@ -340,7 +351,14 @@
static int audit_callback(void *data, security_class_t cls, char *buf, size_t len)
{
- snprintf(buf, len, "service=%s", !data ? "NULL" : (char *)data);
+ struct audit_data *ad = (struct audit_data *)data;
+
+ if (!ad || !ad->name) {
+ ALOGE("No service manager audit data");
+ return 0;
+ }
+
+ snprintf(buf, len, "service=%s pid=%d uid=%d", ad->name, ad->pid, ad->uid);
return 0;
}
diff --git a/include/android/keycodes.h b/include/android/keycodes.h
index ac07190..67e28da 100644
--- a/include/android/keycodes.h
+++ b/include/android/keycodes.h
@@ -751,7 +751,13 @@
* Steps media backward one from at a time. */
AKEYCODE_MEDIA_STEP_BACKWARD = 275,
/** Put device to sleep unless a wakelock is held. */
- AKEYCODE_SOFT_SLEEP = 276
+ AKEYCODE_SOFT_SLEEP = 276,
+ /** Cut key. */
+ AKEYCODE_CUT = 277,
+ /** Copy key. */
+ AKEYCODE_COPY = 278,
+ /** Paste key. */
+ AKEYCODE_PASTE = 279
// 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/binder/IBinder.h b/include/binder/IBinder.h
index 43b6543..97f1fc2 100644
--- a/include/binder/IBinder.h
+++ b/include/binder/IBinder.h
@@ -33,6 +33,7 @@
class BpBinder;
class IInterface;
class Parcel;
+class IResultReceiver;
/**
* Base class and low-level protocol for a remotable object.
@@ -50,6 +51,7 @@
PING_TRANSACTION = B_PACK_CHARS('_','P','N','G'),
DUMP_TRANSACTION = B_PACK_CHARS('_','D','M','P'),
+ SHELL_COMMAND_TRANSACTION = B_PACK_CHARS('_','C','M','D'),
INTERFACE_TRANSACTION = B_PACK_CHARS('_', 'N', 'T', 'F'),
SYSPROPS_TRANSACTION = B_PACK_CHARS('_', 'S', 'P', 'R'),
@@ -75,6 +77,9 @@
virtual bool isBinderAlive() const = 0;
virtual status_t pingBinder() = 0;
virtual status_t dump(int fd, const Vector<String16>& args) = 0;
+ static status_t shellCommand(const sp<IBinder>& target, int in, int out, int err,
+ Vector<String16>& args,
+ const sp<IResultReceiver>& resultReceiver);
virtual status_t transact( uint32_t code,
const Parcel& data,
diff --git a/include/binder/IResultReceiver.h b/include/binder/IResultReceiver.h
new file mode 100644
index 0000000..02dc6a6
--- /dev/null
+++ b/include/binder/IResultReceiver.h
@@ -0,0 +1,55 @@
+/*
+ * 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_IRESULT_RECEIVER_H
+#define ANDROID_IRESULT_RECEIVER_H
+
+#include <binder/IInterface.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class IResultReceiver : public IInterface
+{
+public:
+ DECLARE_META_INTERFACE(ResultReceiver);
+
+ virtual void send(int32_t resultCode) = 0;
+
+ enum {
+ OP_SEND = IBinder::FIRST_CALL_TRANSACTION
+ };
+};
+
+// ----------------------------------------------------------------------
+
+class BnResultReceiver : public BnInterface<IResultReceiver>
+{
+public:
+ virtual status_t onTransact( uint32_t code,
+ const Parcel& data,
+ Parcel* reply,
+ uint32_t flags = 0);
+};
+
+// ----------------------------------------------------------------------
+
+}; // namespace android
+
+#endif // ANDROID_IRESULT_RECEIVER_H
+
diff --git a/include/binder/Parcel.h b/include/binder/Parcel.h
index 3ada1e9..7b80dd9 100644
--- a/include/binder/Parcel.h
+++ b/include/binder/Parcel.h
@@ -17,6 +17,8 @@
#ifndef ANDROID_PARCEL_H
#define ANDROID_PARCEL_H
+#include <vector>
+
#include <cutils/native_handle.h>
#include <utils/Errors.h>
#include <utils/RefBase.h>
@@ -108,6 +110,18 @@
status_t writeWeakBinder(const wp<IBinder>& val);
status_t writeInt32Array(size_t len, const int32_t *val);
status_t writeByteArray(size_t len, const uint8_t *val);
+ status_t writeBool(bool val);
+ status_t writeChar(char16_t val);
+ status_t writeByte(int8_t val);
+
+ status_t writeByteVector(const std::vector<int8_t>& val);
+ status_t writeInt32Vector(const std::vector<int32_t>& val);
+ status_t writeInt64Vector(const std::vector<int64_t>& val);
+ status_t writeFloatVector(const std::vector<float>& val);
+ status_t writeDoubleVector(const std::vector<double>& val);
+ status_t writeBoolVector(const std::vector<bool>& val);
+ status_t writeCharVector(const std::vector<char16_t>& val);
+ status_t writeString16Vector(const std::vector<String16>& val);
template<typename T>
status_t write(const Flattenable<T>& val);
@@ -118,7 +132,7 @@
// Place a native_handle into the parcel (the native_handle's file-
// descriptors are dup'ed, so it is safe to delete the native_handle
- // when this function returns).
+ // when this function returns).
// Doesn't take ownership of the native_handle.
status_t writeNativeHandle(const native_handle* handle);
@@ -169,14 +183,30 @@
status_t readDouble(double *pArg) const;
intptr_t readIntPtr() const;
status_t readIntPtr(intptr_t *pArg) const;
+ bool readBool() const;
+ status_t readBool(bool *pArg) const;
+ char16_t readChar() const;
+ status_t readChar(char16_t *pArg) const;
+ int8_t readByte() const;
+ status_t readByte(int8_t *pArg) const;
const char* readCString() const;
String8 readString8() const;
String16 readString16() const;
+ status_t readString16(String16* pArg) const;
const char16_t* readString16Inplace(size_t* outLen) const;
sp<IBinder> readStrongBinder() const;
wp<IBinder> readWeakBinder() const;
+ status_t readByteVector(std::vector<int8_t>* val) const;
+ status_t readInt32Vector(std::vector<int32_t>* val) const;
+ status_t readInt64Vector(std::vector<int64_t>* val) const;
+ status_t readFloatVector(std::vector<float>* val) const;
+ status_t readDoubleVector(std::vector<double>* val) const;
+ status_t readBoolVector(std::vector<bool>* val) const;
+ status_t readCharVector(std::vector<char16_t>* val) const;
+ status_t readString16Vector(std::vector<String16>* val) const;
+
template<typename T>
status_t read(Flattenable<T>& val) const;
@@ -342,9 +372,11 @@
private:
size_t mBlobAshmemSize;
+ size_t mOpenAshmemSize;
public:
size_t getBlobAshmemSize() const;
+ size_t getOpenAshmemSize() const;
};
// ---------------------------------------------------------------------------
@@ -412,9 +444,9 @@
// Generic acquire and release of objects.
void acquire_object(const sp<ProcessState>& proc,
- const flat_binder_object& obj, const void* who);
+ const flat_binder_object& obj, const void* who, size_t* outAshmemSize);
void release_object(const sp<ProcessState>& proc,
- const flat_binder_object& obj, const void* who);
+ const flat_binder_object& obj, const void* who, size_t* outAshmemSize);
void flatten_binder(const sp<ProcessState>& proc,
const sp<IBinder>& binder, flat_binder_object* out);
diff --git a/include/gui/IGraphicBufferProducer.h b/include/gui/IGraphicBufferProducer.h
index be1874a..b8cba2f 100644
--- a/include/gui/IGraphicBufferProducer.h
+++ b/include/gui/IGraphicBufferProducer.h
@@ -113,14 +113,10 @@
// allow for the asynchronous behavior. If it is not enabled queue/dequeue
// calls may block.
//
- // This function should not be called when there are any currently dequeued
- // buffer slots, doing so will result in a BAD_VALUE error.
- //
// Return of a value other than NO_ERROR means an error has occurred:
// * NO_INIT - the buffer queue has been abandoned.
- // * BAD_VALUE - one of the below conditions occurred:
- // * client has one or more buffers dequeued
- // * this call would cause the maxBufferCount value to be exceeded
+ // * BAD_VALUE - this call would cause the maxBufferCount value to be
+ // exceeded
virtual status_t setAsyncMode(bool async) = 0;
// dequeueBuffer requests a new buffer slot for the client to use. Ownership
diff --git a/include/input/Input.h b/include/input/Input.h
index 093219a..aca8112 100644
--- a/include/input/Input.h
+++ b/include/input/Input.h
@@ -111,6 +111,11 @@
#define MAX_POINTERS 16
/*
+ * Maximum number of samples supported per motion event.
+ */
+#define MAX_SAMPLES UINT16_MAX
+
+/*
* Maximum pointer id value supported in a motion event.
* Smallest pointer id is 0.
* (This is limited by our use of BitSet32 to track pointer assignments.)
diff --git a/include/input/InputEventLabels.h b/include/input/InputEventLabels.h
index efc1687..b7012eb 100644
--- a/include/input/InputEventLabels.h
+++ b/include/input/InputEventLabels.h
@@ -316,6 +316,9 @@
DEFINE_KEYCODE(MEDIA_STEP_FORWARD),
DEFINE_KEYCODE(MEDIA_STEP_BACKWARD),
DEFINE_KEYCODE(SOFT_SLEEP),
+ DEFINE_KEYCODE(CUT),
+ DEFINE_KEYCODE(COPY),
+ DEFINE_KEYCODE(PASTE),
{ NULL, 0 }
};
diff --git a/include/input/KeyCharacterMap.h b/include/input/KeyCharacterMap.h
index 111139b..7935927 100644
--- a/include/input/KeyCharacterMap.h
+++ b/include/input/KeyCharacterMap.h
@@ -31,6 +31,9 @@
#include <utils/Unicode.h>
#include <utils/RefBase.h>
+// Maximum number of keys supported by KeyCharacterMaps
+#define MAX_KEYS 8192
+
namespace android {
/**
@@ -124,6 +127,11 @@
* the mapping in some way. */
status_t mapKey(int32_t scanCode, int32_t usageCode, int32_t* outKeyCode) const;
+ /* Tries to find a replacement key code for a given key code and meta state
+ * in character map. */
+ void tryRemapKey(int32_t scanCode, int32_t metaState,
+ int32_t* outKeyCode, int32_t* outMetaState) const;
+
#ifdef __ANDROID__
/* Reads a key map from a parcel. */
static sp<KeyCharacterMap> readFromParcel(Parcel* parcel);
@@ -151,6 +159,9 @@
/* The fallback keycode if the key is not handled. */
int32_t fallbackKeyCode;
+
+ /* The replacement keycode if the key has to be replaced outright. */
+ int32_t replacementKeyCode;
};
struct Key {
diff --git a/include/input/Keyboard.h b/include/input/Keyboard.h
index 519bb22..d4903e9 100644
--- a/include/input/Keyboard.h
+++ b/include/input/Keyboard.h
@@ -88,6 +88,13 @@
extern int32_t updateMetaState(int32_t keyCode, bool down, int32_t oldMetaState);
/**
+ * Normalizes the meta state such that if either the left or right modifier
+ * meta state bits are set then the result will also include the universal
+ * bit for that modifier.
+ */
+extern int32_t normalizeMetaState(int32_t oldMetaState);
+
+/**
* Returns true if a key is a meta key like ALT or CAPS_LOCK.
*/
extern bool isMetaKey(int32_t keyCode);
diff --git a/libs/binder/Android.mk b/libs/binder/Android.mk
index ce29ea6..19298e2 100644
--- a/libs/binder/Android.mk
+++ b/libs/binder/Android.mk
@@ -27,6 +27,7 @@
IPCThreadState.cpp \
IPermissionController.cpp \
IProcessInfoService.cpp \
+ IResultReceiver.cpp \
ProcessInfoService.cpp \
IServiceManager.cpp \
MemoryDealer.cpp \
diff --git a/libs/binder/Binder.cpp b/libs/binder/Binder.cpp
index e39093d..c4d47ca 100644
--- a/libs/binder/Binder.cpp
+++ b/libs/binder/Binder.cpp
@@ -20,6 +20,7 @@
#include <utils/misc.h>
#include <binder/BpBinder.h>
#include <binder/IInterface.h>
+#include <binder/IResultReceiver.h>
#include <binder/Parcel.h>
#include <stdio.h>
@@ -59,6 +60,24 @@
return false;
}
+
+status_t IBinder::shellCommand(const sp<IBinder>& target, int in, int out, int err,
+ Vector<String16>& args, const sp<IResultReceiver>& resultReceiver)
+{
+ Parcel send;
+ Parcel reply;
+ send.writeFileDescriptor(in);
+ send.writeFileDescriptor(out);
+ send.writeFileDescriptor(err);
+ const size_t numArgs = args.size();
+ send.writeInt32(numArgs);
+ for (size_t i = 0; i < numArgs; i++) {
+ send.writeString16(args[i]);
+ }
+ send.writeStrongBinder(resultReceiver != NULL ? IInterface::asBinder(resultReceiver) : NULL);
+ return target->transact(SHELL_COMMAND_TRANSACTION, send, &reply);
+}
+
// ---------------------------------------------------------------------------
class BBinder::Extras
@@ -129,7 +148,7 @@
return INVALID_OPERATION;
}
- status_t BBinder::dump(int /*fd*/, const Vector<String16>& /*args*/)
+status_t BBinder::dump(int /*fd*/, const Vector<String16>& /*args*/)
{
return NO_ERROR;
}
@@ -204,6 +223,25 @@
return dump(fd, args);
}
+ case SHELL_COMMAND_TRANSACTION: {
+ int in = data.readFileDescriptor();
+ int out = data.readFileDescriptor();
+ int err = data.readFileDescriptor();
+ int argc = data.readInt32();
+ Vector<String16> args;
+ for (int i = 0; i < argc && data.dataAvail() > 0; i++) {
+ args.add(data.readString16());
+ }
+ sp<IResultReceiver> resultReceiver = IResultReceiver::asInterface(
+ data.readStrongBinder());
+
+ // XXX can't add virtuals until binaries are updated.
+ //return shellCommand(in, out, err, args, resultReceiver);
+ if (resultReceiver != NULL) {
+ resultReceiver->send(INVALID_OPERATION);
+ }
+ }
+
case SYSPROPS_TRANSACTION: {
report_sysprop_change();
return NO_ERROR;
diff --git a/libs/binder/BpBinder.cpp b/libs/binder/BpBinder.cpp
index 345ba20..c0e0296 100644
--- a/libs/binder/BpBinder.cpp
+++ b/libs/binder/BpBinder.cpp
@@ -20,6 +20,7 @@
#include <binder/BpBinder.h>
#include <binder/IPCThreadState.h>
+#include <binder/IResultReceiver.h>
#include <utils/Log.h>
#include <stdio.h>
diff --git a/libs/binder/Debug.cpp b/libs/binder/Debug.cpp
index bdb7182..a8f2da5 100644
--- a/libs/binder/Debug.cpp
+++ b/libs/binder/Debug.cpp
@@ -138,7 +138,7 @@
*pos = 0;
return pos;
}
-
+
if( fullContext ) {
*pos++ = '0';
*pos++ = 'x';
@@ -167,21 +167,21 @@
if (func == NULL) func = defaultPrintFunc;
size_t offset;
-
+
unsigned char *pos = (unsigned char *)buf;
-
+
if (pos == NULL) {
if (singleLineBytesCutoff < 0) func(cookie, "\n");
func(cookie, "(NULL)");
return;
}
-
+
if (length == 0) {
if (singleLineBytesCutoff < 0) func(cookie, "\n");
func(cookie, "(empty)");
return;
}
-
+
if ((int32_t)length < 0) {
if (singleLineBytesCutoff < 0) func(cookie, "\n");
char buf[64];
@@ -189,12 +189,12 @@
func(cookie, buf);
return;
}
-
+
char buffer[256];
static const size_t maxBytesPerLine = (sizeof(buffer)-1-11-4)/(3+1);
-
+
if (bytesPerLine > maxBytesPerLine) bytesPerLine = maxBytesPerLine;
-
+
const bool oneLine = (int32_t)length <= singleLineBytesCutoff;
bool newLine = false;
if (cStyle) {
@@ -205,7 +205,7 @@
func(cookie, "\n");
newLine = true;
}
-
+
for (offset = 0; ; offset += bytesPerLine, pos += bytesPerLine) {
long remain = length;
@@ -217,21 +217,20 @@
size_t index;
size_t word;
-
+
for (word = 0; word < bytesPerLine; ) {
const size_t startIndex = word+(alignment-(alignment?1:0));
- const ssize_t dir = -1;
for (index = 0; index < alignment || (alignment == 0 && index < bytesPerLine); index++) {
-
+
if (!cStyle) {
if (index == 0 && word > 0 && alignment > 0) {
*c++ = ' ';
}
-
+
if (remain-- > 0) {
- const unsigned char val = *(pos+startIndex+(index*dir));
+ const unsigned char val = *(pos+startIndex-index);
*c++ = makehexdigit(val>>4);
*c++ = makehexdigit(val);
} else if (!oneLine) {
@@ -248,14 +247,14 @@
*c++ = '0';
*c++ = 'x';
}
- const unsigned char val = *(pos+startIndex+(index*dir));
+ const unsigned char val = *(pos+startIndex-index);
*c++ = makehexdigit(val>>4);
*c++ = makehexdigit(val);
remain--;
}
}
}
-
+
word += index;
}
@@ -272,7 +271,7 @@
*c++ = ' ';
}
}
-
+
*c++ = '\'';
if (length > bytesPerLine) *c++ = '\n';
} else {
@@ -284,7 +283,7 @@
*c = 0;
func(cookie, buffer);
newLine = true;
-
+
if (length <= bytesPerLine) break;
length -= bytesPerLine;
}
diff --git a/libs/binder/IResultReceiver.cpp b/libs/binder/IResultReceiver.cpp
new file mode 100644
index 0000000..2a22b69
--- /dev/null
+++ b/libs/binder/IResultReceiver.cpp
@@ -0,0 +1,69 @@
+/*
+ * 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.
+ */
+
+#define LOG_TAG "ResultReceiver"
+
+#include <binder/IResultReceiver.h>
+
+#include <utils/Log.h>
+#include <binder/Parcel.h>
+#include <utils/String8.h>
+
+#include <private/binder/Static.h>
+
+namespace android {
+
+// ----------------------------------------------------------------------
+
+class BpResultReceiver : public BpInterface<IResultReceiver>
+{
+public:
+ BpResultReceiver(const sp<IBinder>& impl)
+ : BpInterface<IResultReceiver>(impl)
+ {
+ }
+
+ virtual void send(int32_t resultCode) {
+ Parcel data;
+ data.writeInterfaceToken(IResultReceiver::getInterfaceDescriptor());
+ data.writeInt32(resultCode);
+ remote()->transact(OP_SEND, data, NULL, IBinder::FLAG_ONEWAY);
+ }
+};
+
+IMPLEMENT_META_INTERFACE(ResultReceiver, "com.android.internal.os.IResultReceiver");
+
+// ----------------------------------------------------------------------
+
+status_t BnResultReceiver::onTransact(
+ uint32_t code, const Parcel& data, Parcel* reply, uint32_t flags)
+{
+ switch(code) {
+ case OP_SEND: {
+ CHECK_INTERFACE(IResultReceiver, data, reply);
+ int32_t resultCode = data.readInt32();
+ send(resultCode);
+ if (reply != NULL) {
+ reply->writeNoException();
+ }
+ return NO_ERROR;
+ } break;
+ default:
+ return BBinder::onTransact(code, data, reply, flags);
+ }
+}
+
+}; // namespace android
diff --git a/libs/binder/IServiceManager.cpp b/libs/binder/IServiceManager.cpp
index 134aadc..61f24d6 100644
--- a/libs/binder/IServiceManager.cpp
+++ b/libs/binder/IServiceManager.cpp
@@ -33,7 +33,7 @@
sp<IServiceManager> defaultServiceManager()
{
if (gDefaultServiceManager != NULL) return gDefaultServiceManager;
-
+
{
AutoMutex _l(gDefaultServiceManagerLock);
while (gDefaultServiceManager == NULL) {
@@ -43,7 +43,7 @@
sleep(1);
}
}
-
+
return gDefaultServiceManager;
}
@@ -67,11 +67,16 @@
bool checkPermission(const String16& permission, pid_t pid, uid_t uid)
{
+#ifdef __BRILLO__
+ // Brillo doesn't currently run ActivityManager or support framework permissions.
+ return true;
+#endif
+
sp<IPermissionController> pc;
gDefaultServiceManagerLock.lock();
pc = gPermissionController;
gDefaultServiceManagerLock.unlock();
-
+
int64_t startTime = 0;
while (true) {
@@ -85,14 +90,14 @@
}
return res;
}
-
+
// Is this a permission failure, or did the controller go away?
if (IInterface::asBinder(pc)->isBinderAlive()) {
ALOGW("Permission failure: %s from uid=%d pid=%d",
String8(permission).string(), uid, pid);
return false;
}
-
+
// Object is dead!
gDefaultServiceManagerLock.lock();
if (gPermissionController == pc) {
@@ -100,7 +105,7 @@
}
gDefaultServiceManagerLock.unlock();
}
-
+
// Need to retrieve the permission controller.
sp<IBinder> binder = defaultServiceManager()->checkService(_permission);
if (binder == NULL) {
@@ -113,7 +118,7 @@
sleep(1);
} else {
pc = interface_cast<IPermissionController>(binder);
- // Install the new permission controller, and try again.
+ // Install the new permission controller, and try again.
gDefaultServiceManagerLock.lock();
gPermissionController = pc;
gDefaultServiceManagerLock.unlock();
diff --git a/libs/binder/Parcel.cpp b/libs/binder/Parcel.cpp
index 8315c58..5a62fce 100644
--- a/libs/binder/Parcel.cpp
+++ b/libs/binder/Parcel.cpp
@@ -96,7 +96,7 @@
};
void acquire_object(const sp<ProcessState>& proc,
- const flat_binder_object& obj, const void* who)
+ const flat_binder_object& obj, const void* who, size_t* outAshmemSize)
{
switch (obj.type) {
case BINDER_TYPE_BINDER:
@@ -123,8 +123,13 @@
return;
}
case BINDER_TYPE_FD: {
- // intentionally blank -- nothing to do to acquire this, but we do
- // recognize it as a legitimate object type.
+ if (obj.cookie != 0) {
+ // If we own an ashmem fd, keep track of how much memory it refers to.
+ int size = ashmem_get_size_region(obj.handle);
+ if (size > 0) {
+ *outAshmemSize += size;
+ }
+ }
return;
}
}
@@ -133,7 +138,7 @@
}
void release_object(const sp<ProcessState>& proc,
- const flat_binder_object& obj, const void* who)
+ const flat_binder_object& obj, const void* who, size_t* outAshmemSize)
{
switch (obj.type) {
case BINDER_TYPE_BINDER:
@@ -160,7 +165,14 @@
return;
}
case BINDER_TYPE_FD: {
- if (obj.cookie != 0) close(obj.handle);
+ if (obj.cookie != 0) {
+ int size = ashmem_get_size_region(obj.handle);
+ if (size > 0) {
+ *outAshmemSize -= size;
+ }
+
+ close(obj.handle);
+ }
return;
}
}
@@ -502,7 +514,7 @@
flat_binder_object* flat
= reinterpret_cast<flat_binder_object*>(mData + off);
- acquire_object(proc, *flat, this);
+ acquire_object(proc, *flat, this, &mOpenAshmemSize);
if (flat->type == BINDER_TYPE_FD) {
// If this is a file descriptor, we need to dup it so the
@@ -715,6 +727,190 @@
return NULL;
}
+status_t Parcel::writeByteVector(const std::vector<int8_t>& val)
+{
+ if (val.size() > std::numeric_limits<int32_t>::max()) {
+ return BAD_VALUE;
+ }
+
+ status_t status = writeInt32(val.size());
+
+ if (status != OK) {
+ return status;
+ }
+
+ for (const auto& item : val) {
+ status = writeByte(item);
+
+ if (status != OK) {
+ return status;
+ }
+ }
+
+ return OK;
+}
+
+status_t Parcel::writeInt32Vector(const std::vector<int32_t>& val)
+{
+ if (val.size() > std::numeric_limits<int32_t>::max()) {
+ return BAD_VALUE;
+ }
+
+ status_t status = writeInt32(val.size());
+
+ if (status != OK) {
+ return status;
+ }
+
+ for (const auto& item : val) {
+ status = writeInt32(item);
+
+ if (status != OK) {
+ return status;
+ }
+ }
+
+ return OK;
+}
+
+status_t Parcel::writeInt64Vector(const std::vector<int64_t>& val)
+{
+ if (val.size() > std::numeric_limits<int32_t>::max()) {
+ return BAD_VALUE;
+ }
+
+ status_t status = writeInt32(val.size());
+
+ if (status != OK) {
+ return status;
+ }
+
+ for (const auto& item : val) {
+ status = writeInt64(item);
+
+ if (status != OK) {
+ return status;
+ }
+ }
+
+ return OK;
+}
+
+status_t Parcel::writeFloatVector(const std::vector<float>& val)
+{
+ if (val.size() > std::numeric_limits<int32_t>::max()) {
+ return BAD_VALUE;
+ }
+
+ status_t status = writeInt32(val.size());
+
+ if (status != OK) {
+ return status;
+ }
+
+ for (const auto& item : val) {
+ status = writeFloat(item);
+
+ if (status != OK) {
+ return status;
+ }
+ }
+
+ return OK;
+}
+
+status_t Parcel::writeDoubleVector(const std::vector<double>& val)
+{
+ if (val.size() > std::numeric_limits<int32_t>::max()) {
+ return BAD_VALUE;
+ }
+
+ status_t status = writeInt32(val.size());
+
+ if (status != OK) {
+ return status;
+ }
+
+ for (const auto& item : val) {
+ status = writeDouble(item);
+
+ if (status != OK) {
+ return status;
+ }
+ }
+
+ return OK;
+}
+
+status_t Parcel::writeBoolVector(const std::vector<bool>& val)
+{
+ if (val.size() > std::numeric_limits<int32_t>::max()) {
+ return BAD_VALUE;
+ }
+
+ status_t status = writeInt32(val.size());
+
+ if (status != OK) {
+ return status;
+ }
+
+ for (const auto& item : val) {
+ status = writeBool(item);
+
+ if (status != OK) {
+ return status;
+ }
+ }
+
+ return OK;
+}
+
+status_t Parcel::writeCharVector(const std::vector<char16_t>& val)
+{
+ if (val.size() > std::numeric_limits<int32_t>::max()) {
+ return BAD_VALUE;
+ }
+
+ status_t status = writeInt32(val.size());
+
+ if (status != OK) {
+ return status;
+ }
+
+ for (const auto& item : val) {
+ status = writeChar(item);
+
+ if (status != OK) {
+ return status;
+ }
+ }
+
+ return OK;
+}
+
+status_t Parcel::writeString16Vector(const std::vector<String16>& val)
+{
+ if (val.size() > std::numeric_limits<int32_t>::max()) {
+ return BAD_VALUE;
+ }
+
+ status_t status = writeInt32(val.size());
+
+ if (status != OK) {
+ return status;
+ }
+
+ for (const auto& item : val) {
+ status = writeString16(item);
+
+ if (status != OK) {
+ return status;
+ }
+ }
+
+ return OK;
+}
+
status_t Parcel::writeInt32(int32_t val)
{
return writeAligned(val);
@@ -758,6 +954,21 @@
return ret;
}
+status_t Parcel::writeBool(bool val)
+{
+ return writeInt32(int32_t(val));
+}
+
+status_t Parcel::writeChar(char16_t val)
+{
+ return writeInt32(int32_t(val));
+}
+
+status_t Parcel::writeByte(int8_t val)
+{
+ return writeInt32(int32_t(val));
+}
+
status_t Parcel::writeInt64(int64_t val)
{
return writeAligned(val);
@@ -1024,7 +1235,7 @@
// Need to write meta-data?
if (nullMetaData || val.binder != 0) {
mObjects[mObjectsSize] = mDataPos;
- acquire_object(ProcessState::self(), val, this);
+ acquire_object(ProcessState::self(), val, this, &mOpenAshmemSize);
mObjectsSize++;
}
@@ -1132,6 +1343,232 @@
return err;
}
+status_t Parcel::readByteVector(std::vector<int8_t>* val) const {
+ val->clear();
+
+ int32_t size;
+ status_t status = readInt32(&size);
+
+ if (status != OK) {
+ return status;
+ }
+
+ if (size < 0) {
+ return BAD_VALUE;
+ }
+
+ val->resize(size);
+
+ for (auto& v : *val) {
+ status = readByte(&v);
+
+ if (status != OK) {
+ return status;
+ }
+ }
+
+ return OK;
+}
+
+status_t Parcel::readInt32Vector(std::vector<int32_t>* val) const {
+ val->clear();
+
+ int32_t size;
+ status_t status = readInt32(&size);
+
+ if (status != OK) {
+ return status;
+ }
+
+ if (size < 0) {
+ return BAD_VALUE;
+ }
+
+ val->resize(size);
+
+ for (auto& v: *val) {
+ status = readInt32(&v);
+
+ if (status != OK) {
+ return status;
+ }
+ }
+
+ return OK;
+}
+
+status_t Parcel::readInt64Vector(std::vector<int64_t>* val) const {
+ val->clear();
+
+ int32_t size;
+ status_t status = readInt32(&size);
+
+ if (status != OK) {
+ return status;
+ }
+
+ if (size < 0) {
+ return BAD_VALUE;
+ }
+
+ val->resize(size);
+
+ for (auto& v : *val) {
+ status = readInt64(&v);
+
+ if (status != OK) {
+ return status;
+ }
+ }
+
+ return OK;
+}
+
+status_t Parcel::readFloatVector(std::vector<float>* val) const {
+ val->clear();
+
+ int32_t size;
+ status_t status = readInt32(&size);
+
+ if (status != OK) {
+ return status;
+ }
+
+ if (size < 0) {
+ return BAD_VALUE;
+ }
+
+ val->resize(size);
+
+ for (auto& v : *val) {
+ status = readFloat(&v);
+
+ if (status != OK) {
+ return status;
+ }
+ }
+
+ return OK;
+}
+
+status_t Parcel::readDoubleVector(std::vector<double>* val) const {
+ val->clear();
+
+ int32_t size;
+ status_t status = readInt32(&size);
+
+ if (status != OK) {
+ return status;
+ }
+
+ if (size < 0) {
+ return BAD_VALUE;
+ }
+
+ val->resize(size);
+
+ for (auto& v : *val) {
+ status = readDouble(&v);
+
+ if (status != OK) {
+ return status;
+ }
+ }
+
+ return OK;
+}
+
+status_t Parcel::readBoolVector(std::vector<bool>* val) const {
+ val->clear();
+
+ int32_t size;
+ status_t status = readInt32(&size);
+
+ if (status != OK) {
+ return status;
+ }
+
+ if (size < 0) {
+ return BAD_VALUE;
+ }
+
+ val->resize(size);
+
+ /* C++ bool handling means a vector of bools isn't necessarily addressable
+ * (we might use individual bits)
+ */
+ for (int32_t i = 0; i < size; size++) {
+ bool data;
+ status = readBool(&data);
+ (*val)[i] = data;
+
+ if (status != OK) {
+ return status;
+ }
+ }
+
+ return OK;
+}
+
+status_t Parcel::readCharVector(std::vector<char16_t>* val) const {
+ val->clear();
+
+ int32_t size;
+ status_t status = readInt32(&size);
+
+ if (status != OK) {
+ return status;
+ }
+
+ if (size < 0) {
+ return BAD_VALUE;
+ }
+
+ val->resize(size);
+
+ for (auto& v : *val) {
+ status = readChar(&v);
+
+ if (status != OK) {
+ return status;
+ }
+ }
+
+ return OK;
+}
+
+status_t Parcel::readString16Vector(std::vector<String16>* val) const {
+ val->clear();
+
+ int32_t size;
+ status_t status = readInt32(&size);
+
+ if (status != OK) {
+ return status;
+ }
+
+ if (size < 0) {
+ return BAD_VALUE;
+ }
+
+ val->reserve(size);
+
+ while (size-- > 0) {
+ const char16_t *data;
+ size_t size;
+ data = readString16Inplace(&size);
+
+ if (data == nullptr) {
+ return UNKNOWN_ERROR;
+ }
+
+ val->emplace_back(data, size);
+ }
+
+ return OK;
+}
+
+
status_t Parcel::readInt32(int32_t *pArg) const
{
return readAligned(pArg);
@@ -1250,6 +1687,44 @@
return readAligned<intptr_t>();
}
+status_t Parcel::readBool(bool *pArg) const
+{
+ int32_t tmp;
+ status_t ret = readInt32(&tmp);
+ *pArg = (tmp != 0);
+ return ret;
+}
+
+bool Parcel::readBool() const
+{
+ return readInt32() != 0;
+}
+
+status_t Parcel::readChar(char16_t *pArg) const
+{
+ int32_t tmp;
+ status_t ret = readInt32(&tmp);
+ *pArg = char16_t(tmp);
+ return ret;
+}
+
+char16_t Parcel::readChar() const
+{
+ return char16_t(readInt32());
+}
+
+status_t Parcel::readByte(int8_t *pArg) const
+{
+ int32_t tmp;
+ status_t ret = readInt32(&tmp);
+ *pArg = int8_t(tmp);
+ return ret;
+}
+
+int8_t Parcel::readByte() const
+{
+ return int8_t(readInt32());
+}
const char* Parcel::readCString() const
{
@@ -1288,6 +1763,19 @@
return String16();
}
+status_t Parcel::readString16(String16* pArg) const
+{
+ size_t len;
+ const char16_t* str = readString16Inplace(&len);
+ if (str) {
+ pArg->setTo(str, len);
+ return 0;
+ } else {
+ *pArg = String16();
+ return UNKNOWN_ERROR;
+ }
+}
+
const char16_t* Parcel::readString16Inplace(size_t* outLen) const
{
int32_t size = readInt32();
@@ -1607,7 +2095,7 @@
i--;
const flat_binder_object* flat
= reinterpret_cast<flat_binder_object*>(data+objects[i]);
- release_object(proc, *flat, this);
+ release_object(proc, *flat, this, &mOpenAshmemSize);
}
}
@@ -1621,7 +2109,7 @@
i--;
const flat_binder_object* flat
= reinterpret_cast<flat_binder_object*>(data+objects[i]);
- acquire_object(proc, *flat, this);
+ acquire_object(proc, *flat, this, &mOpenAshmemSize);
}
}
@@ -1809,7 +2297,7 @@
// will need to rescan because we may have lopped off the only FDs
mFdsKnown = false;
}
- release_object(proc, *flat, this);
+ release_object(proc, *flat, this, &mOpenAshmemSize);
}
binder_size_t* objects =
(binder_size_t*)realloc(mObjects, objectsSize*sizeof(binder_size_t));
@@ -1896,6 +2384,7 @@
mAllowFds = true;
mOwner = NULL;
mBlobAshmemSize = 0;
+ mOpenAshmemSize = 0;
}
void Parcel::scanForFds() const
@@ -1918,6 +2407,11 @@
return mBlobAshmemSize;
}
+size_t Parcel::getOpenAshmemSize() const
+{
+ return mOpenAshmemSize;
+}
+
// --- Parcel::Blob ---
Parcel::Blob::Blob() :
diff --git a/libs/gui/BufferQueueProducer.cpp b/libs/gui/BufferQueueProducer.cpp
index deec330..0cb018c 100644
--- a/libs/gui/BufferQueueProducer.cpp
+++ b/libs/gui/BufferQueueProducer.cpp
@@ -159,14 +159,6 @@
return NO_INIT;
}
- // There must be no dequeued buffers when changing the async mode.
- for (int s = 0; s < BufferQueueDefs::NUM_BUFFER_SLOTS; ++s) {
- if (mSlots[s].mBufferState == BufferSlot::DEQUEUED) {
- BQ_LOGE("setAsyncMode: buffer owned by producer");
- return BAD_VALUE;
- }
- }
-
if ((mCore->mMaxAcquiredBufferCount + mCore->mMaxDequeuedBufferCount +
(async || mCore->mDequeueBufferCannotBlock ? 1 : 0)) >
mCore->mMaxBufferCount) {
diff --git a/libs/gui/Sensor.cpp b/libs/gui/Sensor.cpp
index 81c0549..0a0fc4b 100644
--- a/libs/gui/Sensor.cpp
+++ b/libs/gui/Sensor.cpp
@@ -246,6 +246,11 @@
break;
}
+ // Set DATA_INJECTION flag here. Defined in HAL 1_4.
+ if (halVersion >= SENSORS_DEVICE_API_VERSION_1_4) {
+ mFlags |= (hwSensor->flags & DATA_INJECTION_MASK);
+ }
+
// For the newer HALs log errors if reporting mask flags are set incorrectly.
if (halVersion >= SENSORS_DEVICE_API_VERSION_1_3) {
// Wake-up flag is set here.
diff --git a/libs/gui/tests/IGraphicBufferProducer_test.cpp b/libs/gui/tests/IGraphicBufferProducer_test.cpp
index 7455cd9..882b14c 100644
--- a/libs/gui/tests/IGraphicBufferProducer_test.cpp
+++ b/libs/gui/tests/IGraphicBufferProducer_test.cpp
@@ -616,10 +616,6 @@
TEST_PRODUCER_USAGE_BITS))) << "slot: " << dequeuedSlot;
}
- // Client has one or more buffers dequeued
- EXPECT_EQ(BAD_VALUE, mProducer->setAsyncMode(false)) << "asyncMode: "
- << false;
-
// Abandon buffer queue
ASSERT_OK(mConsumer->consumerDisconnect());
diff --git a/libs/gui/tests/SurfaceTextureGLThreadToGL_test.cpp b/libs/gui/tests/SurfaceTextureGLThreadToGL_test.cpp
index b4e25f3..c4d0aaa 100644
--- a/libs/gui/tests/SurfaceTextureGLThreadToGL_test.cpp
+++ b/libs/gui/tests/SurfaceTextureGLThreadToGL_test.cpp
@@ -31,6 +31,8 @@
}
};
+ SetUpWindowAndContext();
+
runProducerThread(new PT());
mFC->waitForFrame();
@@ -50,6 +52,8 @@
}
};
+ SetUpWindowAndContext();
+
runProducerThread(new PT());
mFC->waitForFrame();
@@ -75,6 +79,8 @@
}
};
+ SetUpWindowAndContext();
+
runProducerThread(new PT());
for (int i = 0; i < NUM_ITERATIONS; i++) {
@@ -104,6 +110,8 @@
}
};
+ SetUpWindowAndContext();
+
runProducerThread(new PT());
for (int i = 0; i < NUM_ITERATIONS; i++) {
@@ -134,6 +142,8 @@
}
};
+ SetUpWindowAndContext();
+
runProducerThread(new PT());
// Allow three frames to be rendered and queued before starting the
diff --git a/libs/gui/tests/SurfaceTextureGLToGL.h b/libs/gui/tests/SurfaceTextureGLToGL.h
index 5a2eff3..5d43a48 100644
--- a/libs/gui/tests/SurfaceTextureGLToGL.h
+++ b/libs/gui/tests/SurfaceTextureGLToGL.h
@@ -34,7 +34,9 @@
virtual void SetUp() {
SurfaceTextureGLTest::SetUp();
+ }
+ void SetUpWindowAndContext() {
mProducerEglSurface = eglCreateWindowSurface(mEglDisplay, mGlConfig,
mANW.get(), NULL);
ASSERT_EQ(EGL_SUCCESS, eglGetError());
diff --git a/libs/gui/tests/SurfaceTextureGLToGL_test.cpp b/libs/gui/tests/SurfaceTextureGLToGL_test.cpp
index b3f6066..c28b4d1 100644
--- a/libs/gui/tests/SurfaceTextureGLToGL_test.cpp
+++ b/libs/gui/tests/SurfaceTextureGLToGL_test.cpp
@@ -33,6 +33,8 @@
// to 2, and max acquired already defaults to 1.
ASSERT_EQ(OK, mSTC->setMaxDequeuedBufferCount(2));
+ SetUpWindowAndContext();
+
// Do the producer side of things
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
mProducerEglSurface, mProducerEglContext));
@@ -85,6 +87,8 @@
// Set max dequeued to 2, and max acquired already defaults to 1.
ASSERT_EQ(OK, mSTC->setMaxDequeuedBufferCount(2));
+ SetUpWindowAndContext();
+
// Do the producer side of things
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
mProducerEglSurface, mProducerEglContext));
@@ -152,6 +156,7 @@
}
TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceUnrefsBuffers) {
+ SetUpWindowAndContext();
sp<GraphicBuffer> buffers[2];
// This test requires async mode to run on a single thread.
@@ -197,6 +202,7 @@
}
TEST_F(SurfaceTextureGLToGLTest, EglDestroySurfaceAfterAbandonUnrefsBuffers) {
+ SetUpWindowAndContext();
sp<GraphicBuffer> buffers[3];
// This test requires async mode to run on a single thread.
@@ -254,6 +260,7 @@
}
TEST_F(SurfaceTextureGLToGLTest, EglMakeCurrentBeforeConsumerDeathUnrefsBuffers) {
+ SetUpWindowAndContext();
sp<GraphicBuffer> buffer;
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
@@ -291,6 +298,7 @@
}
TEST_F(SurfaceTextureGLToGLTest, EglMakeCurrentAfterConsumerDeathUnrefsBuffers) {
+ SetUpWindowAndContext();
sp<GraphicBuffer> buffer;
EXPECT_TRUE(eglMakeCurrent(mEglDisplay, mProducerEglSurface,
@@ -335,6 +343,8 @@
// Set max dequeued to 2, and max acquired already defaults to 1.
ASSERT_EQ(OK, mSTC->setMaxDequeuedBufferCount(2));
+ SetUpWindowAndContext();
+
// Set the user buffer size.
native_window_set_buffers_user_dimensions(mANW.get(), texWidth, texHeight);
@@ -393,6 +403,8 @@
// Set max dequeued to 2, and max acquired already defaults to 1.
ASSERT_EQ(OK, mSTC->setMaxDequeuedBufferCount(2));
+ SetUpWindowAndContext();
+
// Set the transform hint.
mST->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_90);
@@ -455,6 +467,8 @@
// Set max dequeued to 2, and max acquired already defaults to 1.
ASSERT_EQ(OK, mSTC->setMaxDequeuedBufferCount(2));
+ SetUpWindowAndContext();
+
// Set the transform hint.
mST->setTransformHint(NATIVE_WINDOW_TRANSFORM_ROT_90);
diff --git a/libs/input/Input.cpp b/libs/input/Input.cpp
index 0155007..a624663 100644
--- a/libs/input/Input.cpp
+++ b/libs/input/Input.cpp
@@ -424,7 +424,8 @@
status_t MotionEvent::readFromParcel(Parcel* parcel) {
size_t pointerCount = parcel->readInt32();
size_t sampleCount = parcel->readInt32();
- if (pointerCount == 0 || pointerCount > MAX_POINTERS || sampleCount == 0) {
+ if (pointerCount == 0 || pointerCount > MAX_POINTERS ||
+ sampleCount == 0 || sampleCount > MAX_SAMPLES) {
return BAD_VALUE;
}
diff --git a/libs/input/KeyCharacterMap.cpp b/libs/input/KeyCharacterMap.cpp
index 732ebd0..fe649fb 100644
--- a/libs/input/KeyCharacterMap.cpp
+++ b/libs/input/KeyCharacterMap.cpp
@@ -332,33 +332,75 @@
if (usageCode) {
ssize_t index = mKeysByUsageCode.indexOfKey(usageCode);
if (index >= 0) {
-#if DEBUG_MAPPING
- ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
- scanCode, usageCode, *outKeyCode);
-#endif
*outKeyCode = mKeysByUsageCode.valueAt(index);
+#if DEBUG_MAPPING
+ ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
+ scanCode, usageCode, *outKeyCode);
+#endif
return OK;
}
}
if (scanCode) {
ssize_t index = mKeysByScanCode.indexOfKey(scanCode);
if (index >= 0) {
-#if DEBUG_MAPPING
- ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
- scanCode, usageCode, *outKeyCode);
-#endif
*outKeyCode = mKeysByScanCode.valueAt(index);
+#if DEBUG_MAPPING
+ ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Result keyCode=%d.",
+ scanCode, usageCode, *outKeyCode);
+#endif
return OK;
}
}
#if DEBUG_MAPPING
- ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode);
+ ALOGD("mapKey: scanCode=%d, usageCode=0x%08x ~ Failed.", scanCode, usageCode);
#endif
*outKeyCode = AKEYCODE_UNKNOWN;
return NAME_NOT_FOUND;
}
+void KeyCharacterMap::tryRemapKey(int32_t keyCode, int32_t metaState,
+ int32_t *outKeyCode, int32_t *outMetaState) const {
+ *outKeyCode = keyCode;
+ *outMetaState = metaState;
+
+ const Key* key;
+ const Behavior* behavior;
+ if (getKeyBehavior(keyCode, metaState, &key, &behavior)) {
+ if (behavior->replacementKeyCode) {
+ *outKeyCode = behavior->replacementKeyCode;
+ int32_t newMetaState = metaState & ~behavior->metaState;
+ // Reset dependent meta states.
+ if (behavior->metaState & AMETA_ALT_ON) {
+ newMetaState &= ~(AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON);
+ }
+ if (behavior->metaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
+ newMetaState &= ~AMETA_ALT_ON;
+ }
+ if (behavior->metaState & AMETA_CTRL_ON) {
+ newMetaState &= ~(AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON);
+ }
+ if (behavior->metaState & (AMETA_CTRL_LEFT_ON | AMETA_CTRL_RIGHT_ON)) {
+ newMetaState &= ~AMETA_CTRL_ON;
+ }
+ if (behavior->metaState & AMETA_SHIFT_ON) {
+ newMetaState &= ~(AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON);
+ }
+ if (behavior->metaState & (AMETA_SHIFT_LEFT_ON | AMETA_SHIFT_RIGHT_ON)) {
+ newMetaState &= ~AMETA_SHIFT_ON;
+ }
+ // ... and put universal bits back if needed
+ *outMetaState = normalizeMetaState(newMetaState);
+ }
+ }
+
+#if DEBUG_MAPPING
+ ALOGD("tryRemapKey: keyCode=%d, metaState=0x%08x ~ "
+ "replacement keyCode=%d, replacement metaState=0x%08x.",
+ keyCode, metaState, *outKeyCode, *outMetaState);
+#endif
+}
+
bool KeyCharacterMap::getKey(int32_t keyCode, const Key** outKey) const {
ssize_t index = mKeys.indexOfKey(keyCode);
if (index >= 0) {
@@ -565,6 +607,10 @@
if (parcel->errorCheck()) {
return NULL;
}
+ if (numKeys > MAX_KEYS) {
+ ALOGE("Too many keys in KeyCharacterMap (%d > %d)", numKeys, MAX_KEYS);
+ return NULL;
+ }
for (size_t i = 0; i < numKeys; i++) {
int32_t keyCode = parcel->readInt32();
@@ -584,6 +630,7 @@
int32_t metaState = parcel->readInt32();
char16_t character = parcel->readInt32();
int32_t fallbackKeyCode = parcel->readInt32();
+ int32_t replacementKeyCode = parcel->readInt32();
if (parcel->errorCheck()) {
return NULL;
}
@@ -592,6 +639,7 @@
behavior->metaState = metaState;
behavior->character = character;
behavior->fallbackKeyCode = fallbackKeyCode;
+ behavior->replacementKeyCode = replacementKeyCode;
if (lastBehavior) {
lastBehavior->next = behavior;
} else {
@@ -624,6 +672,7 @@
parcel->writeInt32(behavior->metaState);
parcel->writeInt32(behavior->character);
parcel->writeInt32(behavior->fallbackKeyCode);
+ parcel->writeInt32(behavior->replacementKeyCode);
}
parcel->writeInt32(0);
}
@@ -655,13 +704,14 @@
// --- KeyCharacterMap::Behavior ---
KeyCharacterMap::Behavior::Behavior() :
- next(NULL), metaState(0), character(0), fallbackKeyCode(0) {
+ next(NULL), metaState(0), character(0), fallbackKeyCode(0), replacementKeyCode(0) {
}
KeyCharacterMap::Behavior::Behavior(const Behavior& other) :
next(other.next ? new Behavior(*other.next) : NULL),
metaState(other.metaState), character(other.character),
- fallbackKeyCode(other.fallbackKeyCode) {
+ fallbackKeyCode(other.fallbackKeyCode),
+ replacementKeyCode(other.replacementKeyCode) {
}
@@ -923,6 +973,7 @@
Behavior behavior;
bool haveCharacter = false;
bool haveFallback = false;
+ bool haveReplacement = false;
do {
char ch = mTokenizer->peekChar();
@@ -939,6 +990,11 @@
mTokenizer->getLocation().string());
return BAD_VALUE;
}
+ if (haveReplacement) {
+ ALOGE("%s: Cannot combine character literal with replace action.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
behavior.character = character;
haveCharacter = true;
} else {
@@ -949,6 +1005,11 @@
mTokenizer->getLocation().string());
return BAD_VALUE;
}
+ if (haveReplacement) {
+ ALOGE("%s: Cannot combine 'none' with replace action.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
haveCharacter = true;
} else if (token == "fallback") {
mTokenizer->skipDelimiters(WHITESPACE);
@@ -960,13 +1021,36 @@
token.string());
return BAD_VALUE;
}
- if (haveFallback) {
- ALOGE("%s: Cannot combine multiple fallback key codes.",
+ if (haveFallback || haveReplacement) {
+ ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
mTokenizer->getLocation().string());
return BAD_VALUE;
}
behavior.fallbackKeyCode = keyCode;
haveFallback = true;
+ } else if (token == "replace") {
+ mTokenizer->skipDelimiters(WHITESPACE);
+ token = mTokenizer->nextToken(WHITESPACE);
+ int32_t keyCode = getKeyCodeByLabel(token.string());
+ if (!keyCode) {
+ ALOGE("%s: Invalid key code label for replace, got '%s'.",
+ mTokenizer->getLocation().string(),
+ token.string());
+ return BAD_VALUE;
+ }
+ if (haveCharacter) {
+ ALOGE("%s: Cannot combine character literal with replace action.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+ if (haveFallback || haveReplacement) {
+ ALOGE("%s: Cannot combine multiple fallback/replacement key codes.",
+ mTokenizer->getLocation().string());
+ return BAD_VALUE;
+ }
+ behavior.replacementKeyCode = keyCode;
+ haveReplacement = true;
+
} else {
ALOGE("%s: Expected a key behavior after ':'.",
mTokenizer->getLocation().string());
@@ -1016,8 +1100,10 @@
newBehavior->next = key->firstBehavior;
key->firstBehavior = newBehavior;
#if DEBUG_PARSER
- ALOGD("Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d.", mKeyCode,
- newBehavior->metaState, newBehavior->character, newBehavior->fallbackKeyCode);
+ ALOGD("Parsed key meta: keyCode=%d, meta=0x%x, char=%d, fallback=%d replace=%d.",
+ mKeyCode,
+ newBehavior->metaState, newBehavior->character,
+ newBehavior->fallbackKeyCode, newBehavior->replacementKeyCode);
#endif
break;
}
diff --git a/libs/input/Keyboard.cpp b/libs/input/Keyboard.cpp
index f4d9507..9a01395 100644
--- a/libs/input/Keyboard.cpp
+++ b/libs/input/Keyboard.cpp
@@ -176,6 +176,11 @@
~(mask | AMETA_ALT_ON | AMETA_SHIFT_ON | AMETA_CTRL_ON | AMETA_META_ON);
}
+ return normalizeMetaState(newMetaState);
+}
+
+int32_t normalizeMetaState(int32_t oldMetaState) {
+ int32_t newMetaState = oldMetaState;
if (newMetaState & (AMETA_ALT_LEFT_ON | AMETA_ALT_RIGHT_ON)) {
newMetaState |= AMETA_ALT_ON;
}
diff --git a/libs/ui/GraphicBuffer.cpp b/libs/ui/GraphicBuffer.cpp
index 72d390c..4fe0946 100644
--- a/libs/ui/GraphicBuffer.cpp
+++ b/libs/ui/GraphicBuffer.cpp
@@ -113,6 +113,7 @@
GraphicBufferAllocator& allocator(GraphicBufferAllocator::get());
allocator.free(handle);
}
+ handle = NULL;
mWrappedBuffer = 0;
}
diff --git a/opengl/libs/EGL/eglApi.cpp b/opengl/libs/EGL/eglApi.cpp
index 7c905ae..fb29276 100644
--- a/opengl/libs/EGL/eglApi.cpp
+++ b/opengl/libs/EGL/eglApi.cpp
@@ -592,15 +592,6 @@
return setError(EGL_BAD_SURFACE, EGL_FALSE);
egl_surface_t * const s = get_surface(surface);
- ANativeWindow* window = s->win.get();
- if (window) {
- int result = native_window_api_disconnect(window, NATIVE_WINDOW_API_EGL);
- if (result != OK) {
- ALOGE("eglDestroySurface: native_window_api_disconnect (win=%p) "
- "failed (%#x)",
- window, result);
- }
- }
EGLBoolean result = s->cnx->egl.eglDestroySurface(dp->disp.dpy, s->surface);
if (result == EGL_TRUE) {
_s.terminate();
diff --git a/services/inputflinger/EventHub.cpp b/services/inputflinger/EventHub.cpp
index 6b60c7c..5859606 100644
--- a/services/inputflinger/EventHub.cpp
+++ b/services/inputflinger/EventHub.cpp
@@ -438,10 +438,12 @@
return false;
}
-status_t EventHub::mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode,
- int32_t* outKeycode, uint32_t* outFlags) const {
+status_t EventHub::mapKey(int32_t deviceId,
+ int32_t scanCode, int32_t usageCode, int32_t metaState,
+ int32_t* outKeycode, int32_t* outMetaState, uint32_t* outFlags) const {
AutoMutex _l(mLock);
Device* device = getDeviceLocked(deviceId);
+ status_t status = NAME_NOT_FOUND;
if (device) {
// Check the key character map first.
@@ -449,22 +451,34 @@
if (kcm != NULL) {
if (!kcm->mapKey(scanCode, usageCode, outKeycode)) {
*outFlags = 0;
- return NO_ERROR;
+ status = NO_ERROR;
}
}
// Check the key layout next.
- if (device->keyMap.haveKeyLayout()) {
+ if (status != NO_ERROR && device->keyMap.haveKeyLayout()) {
if (!device->keyMap.keyLayoutMap->mapKey(
scanCode, usageCode, outKeycode, outFlags)) {
- return NO_ERROR;
+ status = NO_ERROR;
+ }
+ }
+
+ if (status == NO_ERROR) {
+ if (kcm != NULL) {
+ kcm->tryRemapKey(*outKeycode, metaState, outKeycode, outMetaState);
+ } else {
+ *outMetaState = metaState;
}
}
}
- *outKeycode = 0;
- *outFlags = 0;
- return NAME_NOT_FOUND;
+ if (status != NO_ERROR) {
+ *outKeycode = 0;
+ *outFlags = 0;
+ *outMetaState = metaState;
+ }
+
+ return status;
}
status_t EventHub::mapAxis(int32_t deviceId, int32_t scanCode, AxisInfo* outAxisInfo) const {
diff --git a/services/inputflinger/EventHub.h b/services/inputflinger/EventHub.h
index 3ec4910..0f94c77 100644
--- a/services/inputflinger/EventHub.h
+++ b/services/inputflinger/EventHub.h
@@ -197,8 +197,9 @@
virtual bool hasInputProperty(int32_t deviceId, int property) const = 0;
- virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode,
- int32_t* outKeycode, uint32_t* outFlags) const = 0;
+ virtual status_t mapKey(int32_t deviceId,
+ int32_t scanCode, int32_t usageCode, int32_t metaState,
+ int32_t* outKeycode, int32_t *outMetaState, uint32_t* outFlags) const = 0;
virtual status_t mapAxis(int32_t deviceId, int32_t scanCode,
AxisInfo* outAxisInfo) const = 0;
@@ -285,8 +286,9 @@
virtual bool hasInputProperty(int32_t deviceId, int property) const;
- virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode,
- int32_t* outKeycode, uint32_t* outFlags) const;
+ virtual status_t mapKey(int32_t deviceId,
+ int32_t scanCode, int32_t usageCode, int32_t metaState,
+ int32_t* outKeycode, int32_t *outMetaState, uint32_t* outFlags) const;
virtual status_t mapAxis(int32_t deviceId, int32_t scanCode,
AxisInfo* outAxisInfo) const;
diff --git a/services/inputflinger/InputReader.cpp b/services/inputflinger/InputReader.cpp
index 36095bf..e10a101 100644
--- a/services/inputflinger/InputReader.cpp
+++ b/services/inputflinger/InputReader.cpp
@@ -2177,13 +2177,7 @@
mCurrentHidUsage = 0;
if (isKeyboardOrGamepadKey(scanCode)) {
- int32_t keyCode;
- uint32_t flags;
- if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, &keyCode, &flags)) {
- keyCode = AKEYCODE_UNKNOWN;
- flags = 0;
- }
- processKey(rawEvent->when, rawEvent->value != 0, keyCode, scanCode, flags);
+ processKey(rawEvent->when, rawEvent->value != 0, scanCode, usageCode);
}
break;
}
@@ -2208,8 +2202,18 @@
|| (scanCode >= BTN_JOYSTICK && scanCode < BTN_DIGI);
}
-void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t keyCode,
- int32_t scanCode, uint32_t policyFlags) {
+void KeyboardInputMapper::processKey(nsecs_t when, bool down, int32_t scanCode,
+ int32_t usageCode) {
+ int32_t keyCode;
+ int32_t keyMetaState;
+ uint32_t policyFlags;
+
+ if (getEventHub()->mapKey(getDeviceId(), scanCode, usageCode, mMetaState,
+ &keyCode, &keyMetaState, &policyFlags)) {
+ keyCode = AKEYCODE_UNKNOWN;
+ keyMetaState = mMetaState;
+ policyFlags = 0;
+ }
if (down) {
// Rotate key codes according to orientation if needed.
@@ -2262,6 +2266,12 @@
if (metaStateChanged) {
mMetaState = newMetaState;
updateLedState(false);
+
+ // If global meta state changed send it along with the key.
+ // If it has not changed then we'll use what keymap gave us,
+ // since key replacement logic might temporarily reset a few
+ // meta bits for given key.
+ keyMetaState = newMetaState;
}
nsecs_t downTime = mDownTime;
@@ -2289,7 +2299,7 @@
NotifyKeyArgs args(when, getDeviceId(), mSource, policyFlags,
down ? AKEY_EVENT_ACTION_DOWN : AKEY_EVENT_ACTION_UP,
- AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, newMetaState, downTime);
+ AKEY_EVENT_FLAG_FROM_SYSTEM, keyCode, scanCode, keyMetaState, downTime);
getListener()->notifyKey(&args);
}
@@ -2952,15 +2962,15 @@
// multitouch. The spot-based presentation relies on being able to accurately
// locate two or more fingers on the touch pad.
mParameters.gestureMode = getEventHub()->hasInputProperty(getDeviceId(), INPUT_PROP_SEMI_MT)
- ? Parameters::GESTURE_MODE_POINTER : Parameters::GESTURE_MODE_SPOTS;
+ ? Parameters::GESTURE_MODE_SINGLE_TOUCH : Parameters::GESTURE_MODE_MULTI_TOUCH;
String8 gestureModeString;
if (getDevice()->getConfiguration().tryGetProperty(String8("touch.gestureMode"),
gestureModeString)) {
- if (gestureModeString == "pointer") {
- mParameters.gestureMode = Parameters::GESTURE_MODE_POINTER;
- } else if (gestureModeString == "spots") {
- mParameters.gestureMode = Parameters::GESTURE_MODE_SPOTS;
+ if (gestureModeString == "single-touch") {
+ mParameters.gestureMode = Parameters::GESTURE_MODE_SINGLE_TOUCH;
+ } else if (gestureModeString == "multi-touch") {
+ mParameters.gestureMode = Parameters::GESTURE_MODE_MULTI_TOUCH;
} else if (gestureModeString != "default") {
ALOGW("Invalid value for touch.gestureMode: '%s'", gestureModeString.string());
}
@@ -3028,11 +3038,11 @@
dump.append(INDENT3 "Parameters:\n");
switch (mParameters.gestureMode) {
- case Parameters::GESTURE_MODE_POINTER:
- dump.append(INDENT4 "GestureMode: pointer\n");
+ case Parameters::GESTURE_MODE_SINGLE_TOUCH:
+ dump.append(INDENT4 "GestureMode: single-touch\n");
break;
- case Parameters::GESTURE_MODE_SPOTS:
- dump.append(INDENT4 "GestureMode: spots\n");
+ case Parameters::GESTURE_MODE_MULTI_TOUCH:
+ dump.append(INDENT4 "GestureMode: multi-touch\n");
break;
default:
assert(false);
@@ -3543,8 +3553,10 @@
virtualKey.scanCode = virtualKeyDefinition.scanCode;
int32_t keyCode;
+ int32_t dummyKeyMetaState;
uint32_t flags;
- if (getEventHub()->mapKey(getDeviceId(), virtualKey.scanCode, 0, &keyCode, &flags)) {
+ if (getEventHub()->mapKey(getDeviceId(), virtualKey.scanCode, 0, 0,
+ &keyCode, &dummyKeyMetaState, &flags)) {
ALOGW(INDENT "VirtualKey %d: could not obtain key code, ignoring",
virtualKey.scanCode);
mVirtualKeys.pop(); // drop the key
@@ -4826,14 +4838,17 @@
}
// Update the pointer presentation and spots.
- if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
- mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_SPOT);
+ if (mParameters.gestureMode == Parameters::GESTURE_MODE_MULTI_TOUCH) {
+ mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
if (finishPreviousGesture || cancelPreviousGesture) {
mPointerController->clearSpots();
}
- mPointerController->setSpots(mPointerGesture.currentGestureCoords,
- mPointerGesture.currentGestureIdToIndex,
- mPointerGesture.currentGestureIdBits);
+
+ if (mPointerGesture.currentGestureMode == PointerGesture::FREEFORM) {
+ mPointerController->setSpots(mPointerGesture.currentGestureCoords,
+ mPointerGesture.currentGestureIdToIndex,
+ mPointerGesture.currentGestureIdBits);
+ }
} else {
mPointerController->setPresentation(PointerControllerInterface::PRESENTATION_POINTER);
}
@@ -4842,9 +4857,8 @@
switch (mPointerGesture.currentGestureMode) {
case PointerGesture::NEUTRAL:
case PointerGesture::QUIET:
- if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS
- && (mPointerGesture.lastGestureMode == PointerGesture::SWIPE
- || mPointerGesture.lastGestureMode == PointerGesture::FREEFORM)) {
+ if (mParameters.gestureMode == Parameters::GESTURE_MODE_MULTI_TOUCH
+ && mPointerGesture.lastGestureMode == PointerGesture::FREEFORM) {
// Remind the user of where the pointer is after finishing a gesture with spots.
mPointerController->unfade(PointerControllerInterface::TRANSITION_GRADUAL);
}
@@ -4854,15 +4868,15 @@
case PointerGesture::BUTTON_CLICK_OR_DRAG:
case PointerGesture::HOVER:
case PointerGesture::PRESS:
+ case PointerGesture::SWIPE:
// Unfade the pointer when the current gesture manipulates the
// area directly under the pointer.
mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
break;
- case PointerGesture::SWIPE:
case PointerGesture::FREEFORM:
// Fade the pointer when the current gesture manipulates a different
// area and there are spots to guide the user experience.
- if (mParameters.gestureMode == Parameters::GESTURE_MODE_SPOTS) {
+ if (mParameters.gestureMode == Parameters::GESTURE_MODE_MULTI_TOUCH) {
mPointerController->fade(PointerControllerInterface::TRANSITION_GRADUAL);
} else {
mPointerController->unfade(PointerControllerInterface::TRANSITION_IMMEDIATE);
diff --git a/services/inputflinger/InputReader.h b/services/inputflinger/InputReader.h
index 7cb4680..3a5c76f 100644
--- a/services/inputflinger/InputReader.h
+++ b/services/inputflinger/InputReader.h
@@ -1154,8 +1154,7 @@
bool isKeyboardOrGamepadKey(int32_t scanCode);
- void processKey(nsecs_t when, bool down, int32_t keyCode, int32_t scanCode,
- uint32_t policyFlags);
+ void processKey(nsecs_t when, bool down, int32_t scanCode, int32_t usageCode);
ssize_t findKeyDown(int32_t scanCode);
@@ -1306,8 +1305,8 @@
bool hasButtonUnderPad;
enum GestureMode {
- GESTURE_MODE_POINTER,
- GESTURE_MODE_SPOTS,
+ GESTURE_MODE_SINGLE_TOUCH,
+ GESTURE_MODE_MULTI_TOUCH,
};
GestureMode gestureMode;
diff --git a/services/inputflinger/tests/InputReader_test.cpp b/services/inputflinger/tests/InputReader_test.cpp
index f34b810..42bc865 100644
--- a/services/inputflinger/tests/InputReader_test.cpp
+++ b/services/inputflinger/tests/InputReader_test.cpp
@@ -518,8 +518,9 @@
return false;
}
- virtual status_t mapKey(int32_t deviceId, int32_t scanCode, int32_t usageCode,
- int32_t* outKeycode, uint32_t* outFlags) const {
+ virtual status_t mapKey(int32_t deviceId,
+ int32_t scanCode, int32_t usageCode, int32_t metaState,
+ int32_t* outKeycode, int32_t *outMetaState, uint32_t* outFlags) const {
Device* device = getDevice(deviceId);
if (device) {
const KeyInfo* key = getKey(device, scanCode, usageCode);
@@ -530,6 +531,9 @@
if (outFlags) {
*outFlags = key->flags;
}
+ if (outMetaState) {
+ *outMetaState = metaState;
+ }
return OK;
}
}