merge in oc-release history after reset to master
diff --git a/Android.bp b/Android.bp
index e039773..8e2c849 100644
--- a/Android.bp
+++ b/Android.bp
@@ -36,6 +36,10 @@
cc_binary {
name: "chre_test_client",
proprietary: true,
+ local_include_dirs: [
+ "chre_api/include/chre_api",
+ "util/include",
+ ],
srcs: [
"host/common/test/chre_test_client.cc",
],
diff --git a/Makefile b/Makefile
index f8a6c99..4066d5b 100644
--- a/Makefile
+++ b/Makefile
@@ -41,6 +41,7 @@
HEXAGON_CFLAGS += -I$(SLPI_PREFIX)/core/api/dal
HEXAGON_CFLAGS += -I$(SLPI_PREFIX)/core/api/mproc
HEXAGON_CFLAGS += -I$(SLPI_PREFIX)/core/api/systemdrivers
+HEXAGON_CFLAGS += -I$(SLPI_PREFIX)/platform/rtld/inc
HEXAGON_CFLAGS += -I$(SLPI_PREFIX)/Sensors/api
HEXAGON_CFLAGS += -I$(SLPI_PREFIX)/Sensors/common/idl/inc
HEXAGON_CFLAGS += -I$(SLPI_PREFIX)/Sensors/common/util/mathtools/inc
diff --git a/apps/gnss_world/gnss_world.cc b/apps/gnss_world/gnss_world.cc
index 291641c..7ebb895 100644
--- a/apps/gnss_world/gnss_world.cc
+++ b/apps/gnss_world/gnss_world.cc
@@ -22,8 +22,6 @@
#define LOG_TAG "[GnssWorld]"
#ifdef CHRE_NANOAPP_INTERNAL
-#include "chre/platform/platform_static_nanoapp_init.h"
-
namespace chre {
namespace {
#endif // CHRE_NANOAPP_INTERNAL
@@ -62,14 +60,16 @@
// TODO: Implement this.
}
-void nanoappStop() {
+void nanoappEnd() {
LOGI("Stopped");
}
#ifdef CHRE_NANOAPP_INTERNAL
-} // namespace
-
-PLATFORM_STATIC_NANOAPP_INIT(GnssWorld);
-
+} // anonymous namespace
} // namespace chre
+
+#include "chre/util/nanoapp/app_id.h"
+#include "chre/platform/static_nanoapp_init.h"
+
+CHRE_STATIC_NANOAPP_INIT(GnssWorld, chre::kGnssWorldAppId, 0);
#endif // CHRE_NANOAPP_INTERNAL
diff --git a/apps/hello_world/Makefile b/apps/hello_world/Makefile
index c98268d..981d01c 100644
--- a/apps/hello_world/Makefile
+++ b/apps/hello_world/Makefile
@@ -5,13 +5,22 @@
# Environment Checks ###########################################################
ifeq ($(CHRE_PREFIX),)
-$(error "The CHRE_PREFIX environment variable must be set to a path to the \
- CHRE project root. Example: export CHRE_PREFIX=$$HOME/chre")
+ifneq ($(ANDROID_BUILD_TOP),)
+CHRE_PREFIX = $(ANDROID_BUILD_TOP)/system/chre
+else
+$(error "You must run 'lunch' to setup ANDROID_BUILD_TOP, or explicitly define \
+ the CHRE_PREFIX environment variable to point to the CHRE root \
+ directory.")
+endif
endif
# Nanoapp Configuration ########################################################
NANOAPP_NAME = hello_world
+NANOAPP_ID = 0x0123456789000001
+NANOAPP_VERSION = 0x00000001
+
+NANOAPP_NAME_STRING = \"Hello\ World\"
# Common Compiler Flags ########################################################
diff --git a/apps/hello_world/hello_world.cc b/apps/hello_world/hello_world.cc
index 71ff230..3b49b75 100644
--- a/apps/hello_world/hello_world.cc
+++ b/apps/hello_world/hello_world.cc
@@ -15,40 +15,43 @@
*/
#include <chre.h>
-#include <cinttypes>
+#include <inttypes.h>
-#include "chre/util/nanoapp/log.h"
-
-#define LOG_TAG "[HelloWorld]"
+/**
+ * @file
+ * A very basic example nanoapp that just logs activity in its entry points.
+ * Note that code wrapped in #ifdef CHRE_NANOAPP_INTERNAL is only relevant when
+ * a nanoapp is to be statically built into the CHRE system binary, which would
+ * make it a "system nanoapp" rather than a true dynamically loadable nanoapp.
+ */
#ifdef CHRE_NANOAPP_INTERNAL
-#include "chre/platform/platform_static_nanoapp_init.h"
-
namespace chre {
namespace {
#endif // CHRE_NANOAPP_INTERNAL
bool nanoappStart() {
- LOGI("App started on platform ID %" PRIx64, chreGetPlatformId());
+ chreLog(CHRE_LOG_INFO, "Hello, world!");
return true;
}
void nanoappHandleEvent(uint32_t senderInstanceId,
uint16_t eventType,
- const void *eventData) {
- uint64_t currentTime = chreGetTime();
- LOGI("Received event 0x%" PRIx16 " at time %" PRIu64,
- eventType, currentTime);
+ const void * /*eventData*/) {
+ chreLog(CHRE_LOG_INFO, "Received event 0x%" PRIx16 " from 0x%" PRIx32 " at "
+ "time %" PRIu64, eventType, senderInstanceId, chreGetTime());
}
-void nanoappStop() {
- LOGI("Stopped");
+void nanoappEnd() {
+ chreLog(CHRE_LOG_INFO, "Goodbye, world!");
}
#ifdef CHRE_NANOAPP_INTERNAL
-} // namespace
-
-PLATFORM_STATIC_NANOAPP_INIT(HelloWorld);
-
+} // anonymous namespace
} // namespace chre
+
+#include "chre/util/nanoapp/app_id.h"
+#include "chre/platform/static_nanoapp_init.h"
+
+CHRE_STATIC_NANOAPP_INIT(HelloWorld, chre::kHelloWorldAppId, 0);
#endif // CHRE_NANOAPP_INTERNAL
diff --git a/apps/imu_cal/imu_cal.cc b/apps/imu_cal/imu_cal.cc
index 127d892..9f540d5 100644
--- a/apps/imu_cal/imu_cal.cc
+++ b/apps/imu_cal/imu_cal.cc
@@ -25,8 +25,6 @@
#define LOG_TAG "[ImuCal]"
#ifdef CHRE_NANOAPP_INTERNAL
-#include "chre/platform/platform_static_nanoapp_init.h"
-
namespace chre {
namespace {
#endif // CHRE_NANOAPP_INTERNAL
@@ -162,15 +160,17 @@
}
}
-void nanoappStop() {
+void nanoappEnd() {
// TODO: Unscribe to sensors
LOGI("Stopped");
}
#ifdef CHRE_NANOAPP_INTERNAL
-} // namespace
-
-PLATFORM_STATIC_NANOAPP_INIT(ImuCal);
-
+} // anonymous namespace
} // namespace chre
+
+#include "chre/util/nanoapp/app_id.h"
+#include "chre/platform/static_nanoapp_init.h"
+
+CHRE_STATIC_NANOAPP_INIT(ImuCal, chre::kImuCalAppId, 0);
#endif // CHRE_NANOAPP_INTERNAL
diff --git a/apps/include/chre/apps/apps.h b/apps/include/chre/apps/apps.h
index 70d4781..61ae234 100644
--- a/apps/include/chre/apps/apps.h
+++ b/apps/include/chre/apps/apps.h
@@ -17,18 +17,19 @@
#ifndef CHRE_APPS_APPS_H_
#define CHRE_APPS_APPS_H_
-#include "chre/platform/platform_nanoapp.h"
+#include "chre/core/nanoapp.h"
+#include "chre/util/unique_ptr.h"
namespace chre {
-extern PlatformNanoapp gNanoappGnssWorld;
-extern PlatformNanoapp gNanoappHelloWorld;
-extern PlatformNanoapp gNanoappImuCal;
-extern PlatformNanoapp gNanoappMessageWorld;
-extern PlatformNanoapp gNanoappSensorWorld;
-extern PlatformNanoapp gNanoappTimerWorld;
-extern PlatformNanoapp gNanoappWifiWorld;
-extern PlatformNanoapp gNanoappWwanWorld;
+extern UniquePtr<Nanoapp> *gNanoappGnssWorld;
+extern UniquePtr<Nanoapp> *gNanoappHelloWorld;
+extern UniquePtr<Nanoapp> *gNanoappImuCal;
+extern UniquePtr<Nanoapp> *gNanoappMessageWorld;
+extern UniquePtr<Nanoapp> *gNanoappSensorWorld;
+extern UniquePtr<Nanoapp> *gNanoappTimerWorld;
+extern UniquePtr<Nanoapp> *gNanoappWifiWorld;
+extern UniquePtr<Nanoapp> *gNanoappWwanWorld;
} // namespace chre
diff --git a/apps/message_world/message_world.cc b/apps/message_world/message_world.cc
index 5bd8b3e..a6ac289 100644
--- a/apps/message_world/message_world.cc
+++ b/apps/message_world/message_world.cc
@@ -22,8 +22,6 @@
#define LOG_TAG "[MsgWorld]"
#ifdef CHRE_NANOAPP_INTERNAL
-#include "chre/platform/platform_static_nanoapp_init.h"
-
namespace chre {
namespace {
#endif // CHRE_NANOAPP_INTERNAL
@@ -75,14 +73,16 @@
}
}
-void nanoappStop() {
+void nanoappEnd() {
LOGI("Stopped");
}
#ifdef CHRE_NANOAPP_INTERNAL
-} // namespace
-
-PLATFORM_STATIC_NANOAPP_INIT(MessageWorld);
-
+} // anonymous namespace
} // namespace chre
+
+#include "chre/util/nanoapp/app_id.h"
+#include "chre/platform/static_nanoapp_init.h"
+
+CHRE_STATIC_NANOAPP_INIT(MessageWorld, chre::kMessageWorldAppId, 0);
#endif // CHRE_NANOAPP_INTERNAL
diff --git a/apps/sensor_world/sensor_world.cc b/apps/sensor_world/sensor_world.cc
index f084626..62aac96 100644
--- a/apps/sensor_world/sensor_world.cc
+++ b/apps/sensor_world/sensor_world.cc
@@ -25,8 +25,6 @@
#define LOG_TAG "[SensorWorld]"
#ifdef CHRE_NANOAPP_INTERNAL
-#include "chre/platform/platform_static_nanoapp_init.h"
-
namespace chre {
namespace {
#endif // CHRE_NANOAPP_INTERNAL
@@ -255,14 +253,16 @@
}
}
-void nanoappStop() {
+void nanoappEnd() {
LOGI("Stopped");
}
#ifdef CHRE_NANOAPP_INTERNAL
-} // namespace
-
-PLATFORM_STATIC_NANOAPP_INIT(SensorWorld);
-
+} // anonymous namespace
} // namespace chre
+
+#include "chre/util/nanoapp/app_id.h"
+#include "chre/platform/static_nanoapp_init.h"
+
+CHRE_STATIC_NANOAPP_INIT(SensorWorld, chre::kSensorWorldAppId, 0);
#endif // CHRE_NANOAPP_INTERNAL
diff --git a/apps/timer_world/timer_world.cc b/apps/timer_world/timer_world.cc
index 5a65231..48dbed2 100644
--- a/apps/timer_world/timer_world.cc
+++ b/apps/timer_world/timer_world.cc
@@ -22,8 +22,6 @@
#define LOG_TAG "[TimerWorld]"
#ifdef CHRE_NANOAPP_INTERNAL
-#include "chre/platform/platform_static_nanoapp_init.h"
-
namespace chre {
namespace {
#endif // CHRE_NANOAPP_INTERNAL
@@ -71,14 +69,16 @@
}
}
-void nanoappStop() {
+void nanoappEnd() {
LOGI("Stopped");
}
#ifdef CHRE_NANOAPP_INTERNAL
-} // namespace
-
-PLATFORM_STATIC_NANOAPP_INIT(TimerWorld);
-
+} // anonymous namespace
} // namespace chre
+
+#include "chre/util/nanoapp/app_id.h"
+#include "chre/platform/static_nanoapp_init.h"
+
+CHRE_STATIC_NANOAPP_INIT(TimerWorld, chre::kTimerWorldAppId, 0);
#endif // CHRE_NANOAPP_INTERNAL
diff --git a/apps/wifi_world/wifi_world.cc b/apps/wifi_world/wifi_world.cc
index 0a0f0f8..0a9e3c5 100644
--- a/apps/wifi_world/wifi_world.cc
+++ b/apps/wifi_world/wifi_world.cc
@@ -26,8 +26,6 @@
//#define WIFI_WORLD_VERBOSE_WIFI_RESULT_LOGS
#ifdef CHRE_NANOAPP_INTERNAL
-#include "chre/platform/platform_static_nanoapp_init.h"
-
namespace chre {
namespace {
#endif // CHRE_NANOAPP_INTERNAL
@@ -214,14 +212,16 @@
}
}
-void nanoappStop() {
+void nanoappEnd() {
LOGI("Wifi world app stopped");
}
#ifdef CHRE_NANOAPP_INTERNAL
-} // namespace
-
-PLATFORM_STATIC_NANOAPP_INIT(WifiWorld);
-
+} // anonymous namespace
} // namespace chre
+
+#include "chre/util/nanoapp/app_id.h"
+#include "chre/platform/static_nanoapp_init.h"
+
+CHRE_STATIC_NANOAPP_INIT(WifiWorld, chre::kWifiWorldAppId, 0);
#endif // CHRE_NANOAPP_INTERNAL
diff --git a/apps/wwan_world/wwan_world.cc b/apps/wwan_world/wwan_world.cc
index a803bb2..7717000 100644
--- a/apps/wwan_world/wwan_world.cc
+++ b/apps/wwan_world/wwan_world.cc
@@ -22,8 +22,6 @@
#define LOG_TAG "[WwanWorld]"
#ifdef CHRE_NANOAPP_INTERNAL
-#include "chre/platform/platform_static_nanoapp_init.h"
-
namespace chre {
namespace {
#endif // CHRE_NANOAPP_INTERNAL
@@ -55,14 +53,16 @@
// TODO: Implement this.
}
-void nanoappStop() {
+void nanoappEnd() {
LOGI("Stopped");
}
#ifdef CHRE_NANOAPP_INTERNAL
-} // namespace
-
-PLATFORM_STATIC_NANOAPP_INIT(WwanWorld);
-
+} // anonymous namespace
} // namespace chre
+
+#include "chre/util/nanoapp/app_id.h"
+#include "chre/platform/static_nanoapp_init.h"
+
+CHRE_STATIC_NANOAPP_INIT(WwanWorld, chre::kWwanWorldAppId, 0);
#endif // CHRE_NANOAPP_INTERNAL
diff --git a/build/app_support/google_slpi/libchre_slpi_skel.so b/build/app_support/google_slpi/libchre_slpi_skel.so
new file mode 100755
index 0000000..05ba1b5
--- /dev/null
+++ b/build/app_support/google_slpi/libchre_slpi_skel.so
Binary files differ
diff --git a/build/arch/x86.mk b/build/arch/x86.mk
index 63858b9..116d8e3 100644
--- a/build/arch/x86.mk
+++ b/build/arch/x86.mk
@@ -22,6 +22,9 @@
# Add x86 compiler flags.
TARGET_CFLAGS += $(X86_CFLAGS)
+# x86 is purely used for testing, so always include debugging symbols
+TARGET_CFLAGS += -g
+
# Enable position independence.
TARGET_CFLAGS += -fpic
diff --git a/build/nanoapp/app.mk b/build/nanoapp/app.mk
index fdb8bcf..0d9be6e 100644
--- a/build/nanoapp/app.mk
+++ b/build/nanoapp/app.mk
@@ -22,6 +22,22 @@
This should be assigned by the Makefile that includes app.mk.")
endif
+ifeq ($(NANOAPP_NAME_STRING),)
+$(error The NANOAPP_NAME_STRING variable must be set to the friendly name of \
+ the nanoapp. This should be assigned by the Makefile that includes \
+ app.mk.)
+endif
+
+ifeq ($(NANOAPP_VENDOR_STRING),)
+$(info NANOAPP_VENDOR_STRING not supplied, defaulting to "Google".)
+NANOAPP_VENDOR_STRING = \"Google\"
+endif
+
+ifeq ($(NANOAPP_IS_SYSTEM_NANOAPP),)
+$(info NANOAPP_IS_SYSTEM_NANOAPP not supplied, defaulting to 0.)
+NANOAPP_IS_SYSTEM_NANOAPP = 0
+endif
+
# Nanoapp Build ################################################################
# This variable indicates to the variants that some post-processing may be
@@ -40,7 +56,10 @@
# Variant-specific Nanoapp Support Source Files ################################
APP_SUPPORT_PATH = $(CHRE_PREFIX)/build/app_support
+DSO_SUPPORT_LIB_PATH = $(CHRE_PREFIX)/platform/shared/nanoapp
+GOOGLE_HEXAGONV60_SLPI_SRCS += $(DSO_SUPPORT_LIB_PATH)/nanoapp_support_lib_dso.c
+GOOGLE_HEXAGONV62_SLPI_SRCS += $(DSO_SUPPORT_LIB_PATH)/nanoapp_support_lib_dso.c
QCOM_HEXAGONV60_NANOHUB_SRCS += $(APP_SUPPORT_PATH)/qcom_nanohub/app_support.cc
# Makefile Includes ############################################################
diff --git a/build/nanoapp/google_slpi.mk b/build/nanoapp/google_slpi.mk
index dfcb317..2e629bb 100644
--- a/build/nanoapp/google_slpi.mk
+++ b/build/nanoapp/google_slpi.mk
@@ -15,6 +15,14 @@
#
################################################################################
+TARGET_CFLAGS += -DNANOAPP_ID=$(NANOAPP_ID)
+TARGET_CFLAGS += -DNANOAPP_VERSION=$(NANOAPP_VERSION)
+TARGET_CFLAGS += -DNANOAPP_VENDOR_STRING=$(NANOAPP_VENDOR_STRING)
+TARGET_CFLAGS += -DNANOAPP_NAME_STRING=$(NANOAPP_NAME_STRING)
+TARGET_CFLAGS += -DNANOAPP_IS_SYSTEM_NANOAPP=$(NANOAPP_IS_SYSTEM_NANOAPP)
+TARGET_CFLAGS += -I$(CHRE_PREFIX)/platform/shared/include
+TARGET_CFLAGS += -I$(CHRE_PREFIX)/util/include
+
ifndef GOOGLE_SLPI_NANOAPP_BUILD_TEMPLATE
define GOOGLE_SLPI_NANOAPP_BUILD_TEMPLATE
diff --git a/build/variant/google_hexagonv60_slpi.mk b/build/variant/google_hexagonv60_slpi.mk
index 410076c..1fe3e43 100644
--- a/build/variant/google_hexagonv60_slpi.mk
+++ b/build/variant/google_hexagonv60_slpi.mk
@@ -11,10 +11,11 @@
HEXAGON_ARCH = v60
ifneq ($(filter $(TARGET_NAME)% all, $(MAKECMDGOALS)),)
-include $(CHRE_PREFIX)/build/arch/hexagon.mk
-include $(CHRE_PREFIX)/build/build_template.mk
-
ifneq ($(IS_NANOAPP_BUILD),)
+TARGET_SO_LATE_LIBS += $(CHRE_PREFIX)/build/app_support/google_slpi/libchre_slpi_skel.so
include $(CHRE_PREFIX)/build/nanoapp/google_slpi.mk
endif
+
+include $(CHRE_PREFIX)/build/arch/hexagon.mk
+include $(CHRE_PREFIX)/build/build_template.mk
endif
diff --git a/build/variant/google_hexagonv62_slpi.mk b/build/variant/google_hexagonv62_slpi.mk
index c55b96d..266bc68 100644
--- a/build/variant/google_hexagonv62_slpi.mk
+++ b/build/variant/google_hexagonv62_slpi.mk
@@ -11,10 +11,11 @@
HEXAGON_ARCH = v62
ifneq ($(filter $(TARGET_NAME)% all, $(MAKECMDGOALS)),)
-include $(CHRE_PREFIX)/build/arch/hexagon.mk
-include $(CHRE_PREFIX)/build/build_template.mk
-
ifneq ($(IS_NANOAPP_BUILD),)
+TARGET_SO_LATE_LIBS += $(CHRE_PREFIX)/build/app_support/google_slpi/libchre_slpi_skel.so
include $(CHRE_PREFIX)/build/nanoapp/google_slpi.mk
endif
+
+include $(CHRE_PREFIX)/build/arch/hexagon.mk
+include $(CHRE_PREFIX)/build/build_template.mk
endif
diff --git a/chre_api/include/chre_api/chre/version.h b/chre_api/include/chre_api/chre/version.h
index 8544749..32b066c 100644
--- a/chre_api/include/chre_api/chre/version.h
+++ b/chre_api/include/chre_api/chre/version.h
@@ -22,7 +22,7 @@
* Definitions and methods for the versioning of the Context Hub Runtime
* Environment.
*
- * The CHRE API versioning pertains to all the chre_*.h files and chre.h.
+ * The CHRE API versioning pertains to all header files in the CHRE API.
*/
#include <stdint.h>
@@ -82,6 +82,41 @@
*/
#define CHRE_API_VERSION CHRE_API_VERSION_1_1
+/**
+ * Utility macro to extract only the API major version of a composite CHRE
+ * version.
+ *
+ * @param version A uint32_t version, e.g. the value returned by
+ * chreGetApiVersion()
+ *
+ * @returns The API major version in the least significant byte, e.g. 0x01
+ */
+#define CHRE_EXTRACT_MAJOR_VERSION(version) \
+ (((version) & UINT32_C(0xFF000000)) >> 24)
+
+/**
+ * Utility macro to extract only the API minor version of a composite CHRE
+ * version.
+ *
+ * @param version A uint32_t version, e.g. the CHRE_API_VERSION constant
+ *
+ * @returns The API minor version in the least significant byte, e.g. 0x01
+ */
+#define CHRE_EXTRACT_MINOR_VERSION(version) \
+ (((version) & UINT32_C(0x00FF0000)) >> 16)
+
+/**
+ * Utility macro to extract only the API minor version of a composite CHRE
+ * version.
+ *
+ * @param version A complete uint32_t version, e.g. the value returned by
+ * chreGetVersion()
+ *
+ * @returns The implementation patch version in the least significant two bytes,
+ * e.g. 0x0123, with all other bytes set to 0
+ */
+#define CHRE_EXTRACT_PATCH_VERSION(version) ((version) & UINT32_C(0xFFFF))
+
/**
* Get the API version the CHRE implementation was compiled against.
diff --git a/core/core.mk b/core/core.mk
index 413eb71..3e60c4e 100644
--- a/core/core.mk
+++ b/core/core.mk
@@ -9,8 +9,10 @@
# Common Source Files ##########################################################
+COMMON_SRCS += core/event.cc
COMMON_SRCS += core/event_loop.cc
COMMON_SRCS += core/event_loop_manager.cc
+COMMON_SRCS += core/event_ref_queue.cc
COMMON_SRCS += core/gnss_request_manager.cc
COMMON_SRCS += core/host_comms_manager.cc
COMMON_SRCS += core/init.cc
diff --git a/core/event.cc b/core/event.cc
new file mode 100644
index 0000000..8af721e
--- /dev/null
+++ b/core/event.cc
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2017 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 "chre/core/event.h"
+
+#include "chre/platform/assert.h"
+
+namespace chre {
+
+Event::Event(uint16_t eventType_, void *eventData_,
+ chreEventCompleteFunction *freeCallback_,
+ uint32_t senderInstanceId_, uint32_t targetInstanceId_)
+ : eventType(eventType_), eventData(eventData_), freeCallback(freeCallback_),
+ senderInstanceId(senderInstanceId_),
+ targetInstanceId(targetInstanceId_) {}
+
+void Event::incrementRefCount() {
+ mRefCount++;
+ CHRE_ASSERT(mRefCount != 0);
+}
+
+void Event::decrementRefCount() {
+ CHRE_ASSERT(mRefCount > 0);
+ mRefCount--;
+}
+
+bool Event::isUnreferenced() const {
+ return (mRefCount == 0);
+}
+
+} // namespace chre
diff --git a/core/event_loop.cc b/core/event_loop.cc
index 51c0c67..7331e28 100644
--- a/core/event_loop.cc
+++ b/core/event_loop.cc
@@ -17,6 +17,7 @@
#include "chre/core/event_loop.h"
#include "chre/core/event.h"
+#include "chre/core/event_loop_manager.h"
#include "chre/core/nanoapp.h"
#include "chre/platform/context.h"
#include "chre/platform/log.h"
@@ -39,7 +40,7 @@
}
bool found = false;
- for (auto& app : mNanoapps) {
+ for (const UniquePtr<Nanoapp>& app : mNanoapps) {
if (app->getAppId() == appId) {
*instanceId = app->getInstanceId();
found = true;
@@ -60,7 +61,7 @@
mNanoappsLock.lock();
}
- for (const auto& nanoapp : mNanoapps) {
+ for (const UniquePtr<Nanoapp>& nanoapp : mNanoapps) {
callback(nanoapp.get(), data);
}
@@ -83,7 +84,7 @@
// there is no safety mechanism that ensures an event is not freed twice,
// or that its free callback is invoked in the proper EventLoop, etc.
Event *event = mEvents.pop();
- for (auto& app : mNanoapps) {
+ for (const UniquePtr<Nanoapp>& app : mNanoapps) {
if ((event->targetInstanceId == chre::kBroadcastInstanceId
&& app->isRegisteredForBroadcastEvent(event->eventType))
|| event->targetInstanceId == app->getInstanceId()) {
@@ -105,53 +106,51 @@
// TODO: most basic round-robin implementation - we might want to have some
// kind of priority in the future, but this should be good enough for now
havePendingEvents = false;
- for (auto& app : mNanoapps) {
+ for (const UniquePtr<Nanoapp>& app : mNanoapps) {
if (app->hasPendingEvent()) {
- // TODO: cleaner way to set/clear this? RAII-style?
- mCurrentApp = app.get();
- Event *event = app->processNextEvent();
- mCurrentApp = nullptr;
-
- if (event->isUnreferenced()) {
- freeEvent(event);
- }
-
- havePendingEvents |= app->hasPendingEvent();
+ havePendingEvents |= deliverNextEvent(app);
}
}
}
+ // Drop any events pending distribution
+ while (!mEvents.empty()) {
+ freeEvent(mEvents.pop());
+ }
+
+ // Stop all running nanoapps
while (!mNanoapps.empty()) {
- stopNanoapp(mNanoapps.front().get());
+ stopNanoapp(mNanoapps.size() - 1);
}
LOGI("Exiting EventLoop");
-
- // TODO: need to purge/cleanup events, etc.
}
-bool EventLoop::startNanoapp(PlatformNanoapp *platformNanoapp) {
- CHRE_ASSERT(platformNanoapp != nullptr);
-
+bool EventLoop::startNanoapp(UniquePtr<Nanoapp>& nanoapp) {
+ CHRE_ASSERT(!nanoapp.isNull());
bool success = false;
- if (!mNanoapps.prepareForPush()) {
+ auto *eventLoopManager = EventLoopManagerSingleton::get();
+ uint32_t existingInstanceId;
+
+ if (nanoapp.isNull()) {
+ // no-op, invalid argument
+ } else if (eventLoopManager->findNanoappInstanceIdByAppId(nanoapp->getAppId(),
+ &existingInstanceId,
+ nullptr)) {
+ LOGE("App with ID 0x%016" PRIx64 " already exists as instance ID 0x%"
+ PRIx32, nanoapp->getAppId(), existingInstanceId);
+ } else if (!mNanoapps.prepareForPush()) {
LOGE("Failed to allocate space for new nanoapp");
} else {
- // TODO: get these parameters from somewhere
- UniquePtr<Nanoapp> nanoapp(0, 1, CHRE_API_VERSION_1_1, getNextInstanceId(),
- true, platformNanoapp);
- if (nanoapp.isNull()) {
- LOGE("Failed to allocate new nanoapp");
+ nanoapp->setInstanceId(eventLoopManager->getNextInstanceId());
+ mCurrentApp = nanoapp.get();
+ success = nanoapp->start();
+ mCurrentApp = nullptr;
+ if (!success) {
+ LOGE("Nanoapp %" PRIu32 " failed to start", nanoapp->getInstanceId());
} else {
- mCurrentApp = nanoapp.get();
- success = nanoapp->start();
- mCurrentApp = nullptr;
- if (!success) {
- LOGE("Nanoapp %" PRIu32 " failed to start", nanoapp->getInstanceId());
- } else {
- LockGuard<Mutex> lock(mNanoappsLock);
- mNanoapps.push_back(std::move(nanoapp));
- }
+ LockGuard<Mutex> lock(mNanoappsLock);
+ mNanoapps.push_back(std::move(nanoapp));
}
}
@@ -159,18 +158,9 @@
}
void EventLoop::stopNanoapp(Nanoapp *nanoapp) {
- CHRE_ASSERT(nanoapp != nullptr);
-
for (size_t i = 0; i < mNanoapps.size(); i++) {
if (nanoapp == mNanoapps[i].get()) {
- {
- LockGuard<Mutex> lock(mNanoappsLock);
- mNanoapps.erase(i);
- }
-
- mCurrentApp = nanoapp;
- nanoapp->stop();
- mCurrentApp = nullptr;
+ stopNanoapp(i);
return;
}
}
@@ -182,20 +172,24 @@
bool EventLoop::postEvent(uint16_t eventType, void *eventData,
chreEventCompleteFunction *freeCallback, uint32_t senderInstanceId,
uint32_t targetInstanceId) {
- // TODO: Consider adding a CHRE_ASSERT(mRunning) here.
bool success = false;
- Event *event = mEventPool.allocate(eventType, eventData, freeCallback,
- senderInstanceId, targetInstanceId);
- if (event != nullptr) {
- success = mEvents.push(event);
- } else {
- LOGE("Failed to allocate event");
+
+ if (mRunning) {
+ Event *event = mEventPool.allocate(eventType, eventData, freeCallback,
+ senderInstanceId, targetInstanceId);
+ if (event != nullptr) {
+ success = mEvents.push(event);
+ } else {
+ LOGE("Failed to allocate event");
+ }
}
+
return success;
}
void EventLoop::stop() {
postEvent(0, nullptr, nullptr, kSystemInstanceId, kSystemInstanceId);
+ // Stop accepting new events and tell the main loop to finish
mRunning = false;
}
@@ -209,25 +203,6 @@
return mNanoapps.size();
}
-uint32_t EventLoop::getNextInstanceId() {
- // This is a simple unique ID generator that checks a newly generated ID
- // against all existing IDs using a search (currently linear search).
- // Instance ID generation will slow with more apps. We generally expect there
- // to be few apps and IDs are generated infrequently.
- //
- // The benefit of generating IDs this way is that there is no memory overhead
- // to track issued IDs.
- uint32_t nextInstanceId = mLastInstanceId + 1;
- while (nextInstanceId == kSystemInstanceId
- || nextInstanceId == kBroadcastInstanceId
- || lookupAppByInstanceId(nextInstanceId) != nullptr) {
- nextInstanceId++;
- }
-
- mLastInstanceId = nextInstanceId;
- return nextInstanceId;
-}
-
TimerPool& EventLoop::getTimerPool() {
return mTimerPool;
}
@@ -247,11 +222,35 @@
return nanoapp;
}
+void EventLoop::freeEvent(Event *event) {
+ if (event->freeCallback != nullptr) {
+ // TODO: find a better way to set the context to the creator of the event
+ mCurrentApp = lookupAppByInstanceId(event->senderInstanceId);
+ event->freeCallback(event->eventType, event->eventData);
+ mCurrentApp = nullptr;
+
+ mEventPool.deallocate(event);
+ }
+}
+
+bool EventLoop::deliverNextEvent(const UniquePtr<Nanoapp>& app) {
+ // TODO: cleaner way to set/clear this? RAII-style?
+ mCurrentApp = app.get();
+ Event *event = app->processNextEvent();
+ mCurrentApp = nullptr;
+
+ if (event->isUnreferenced()) {
+ freeEvent(event);
+ }
+
+ return app->hasPendingEvent();
+}
+
Nanoapp *EventLoop::lookupAppByInstanceId(uint32_t instanceId) {
// The system instance ID always has nullptr as its Nanoapp pointer, so can
// skip iterating through the nanoapp list for that case
if (instanceId != kSystemInstanceId) {
- for (auto& app : mNanoapps) {
+ for (const UniquePtr<Nanoapp>& app : mNanoapps) {
if (app->getInstanceId() == instanceId) {
return app.get();
}
@@ -261,14 +260,32 @@
return nullptr;
}
-void EventLoop::freeEvent(Event *event) {
- if (event->freeCallback != nullptr) {
- // TODO: find a better way to set the context to the creator of the event
- mCurrentApp = lookupAppByInstanceId(event->senderInstanceId);
- event->freeCallback(event->eventType, event->eventData);
- mCurrentApp = nullptr;
+void EventLoop::stopNanoapp(size_t index) {
+ const UniquePtr<Nanoapp>& nanoapp = mNanoapps[index];
- mEventPool.deallocate(event);
+ // Process any events pending in this app's queue. Note that since we're
+ // running in the context of this EventLoop, no new events will be added to
+ // this nanoapp's event queue while we're doing this, so once it's empty, we
+ // can be assured it will stay that way.
+ while (nanoapp->hasPendingEvent()) {
+ deliverNextEvent(nanoapp);
+ }
+
+ // TODO: to safely stop a nanoapp while the EventLoop is still running, we
+ // need to deliver/purge any events that the nanoapp sent itself prior to
+ // calling end(), so that we won't try to invoke a free callback after
+ // unloading the nanoapp where that callback resides. Likewise, we need to
+ // make sure any messages to the host from this nanoapp are flushed as well.
+
+ // Let the app know it's going away
+ mCurrentApp = nanoapp.get();
+ nanoapp->end();
+ mCurrentApp = nullptr;
+
+ // Destroy the Nanoapp instance
+ {
+ LockGuard<Mutex> lock(mNanoappsLock);
+ mNanoapps.erase(index);
}
}
diff --git a/core/event_loop_manager.cc b/core/event_loop_manager.cc
index 6d7b5b5..cc57a19 100644
--- a/core/event_loop_manager.cc
+++ b/core/event_loop_manager.cc
@@ -17,6 +17,7 @@
#include "chre/core/event_loop_manager.h"
#include "chre/platform/context.h"
+#include "chre/platform/fatal_error.h"
#include "chre/util/lock_guard.h"
namespace chre {
@@ -36,7 +37,7 @@
// support multiple EventLoop instances, for example the Event freeing
// mechanism is not thread-safe.
CHRE_ASSERT(mEventLoops.empty());
- if (!mEventLoops.emplace_back()) {
+ if (!mEventLoops.emplace_back(MakeUnique<EventLoop>())) {
return nullptr;
}
@@ -85,6 +86,23 @@
return nanoapp;
}
+uint32_t EventLoopManager::getNextInstanceId() {
+ // TODO: this needs to be an atomic integer when we have > 1 event loop, or
+ // use a mutex
+ ++mLastInstanceId;
+
+ // ~4 billion instance IDs should be enough for anyone... if we need to
+ // support wraparound for stress testing load/unload, then we can set a flag
+ // when wraparound occurs and use EventLoop::findNanoappByInstanceId to ensure
+ // we avoid conflicts
+ if (mLastInstanceId == kBroadcastInstanceId
+ || mLastInstanceId == kSystemInstanceId) {
+ FATAL_ERROR("Exhausted instance IDs!");
+ }
+
+ return mLastInstanceId;
+}
+
bool EventLoopManager::postEvent(uint16_t eventType, void *eventData,
chreEventCompleteFunction *freeCallback,
uint32_t senderInstanceId,
diff --git a/core/event_ref_queue.cc b/core/event_ref_queue.cc
new file mode 100644
index 0000000..68cec92
--- /dev/null
+++ b/core/event_ref_queue.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2017 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 "chre/core/event_ref_queue.h"
+
+#include "chre/platform/assert.h"
+
+namespace chre {
+
+EventRefQueue::~EventRefQueue() {
+ CHRE_ASSERT_LOG(empty(), "Potentially leaking events if queue not empty "
+ "when destroyed");
+}
+
+bool EventRefQueue::empty() const {
+ return mQueue.empty();
+}
+
+bool EventRefQueue::push(Event *event) {
+ CHRE_ASSERT(event != nullptr);
+
+ bool pushed = mQueue.push(event);
+ if (pushed) {
+ event->incrementRefCount();
+ }
+
+ return pushed;
+}
+
+Event *EventRefQueue::pop() {
+ CHRE_ASSERT(!mQueue.empty());
+
+ Event *event = mQueue.front();
+ mQueue.pop();
+ event->decrementRefCount();
+
+ return event;
+}
+
+} // namespace chre
diff --git a/core/include/chre/core/event.h b/core/include/chre/core/event.h
index f20a196..d073c63 100644
--- a/core/include/chre/core/event.h
+++ b/core/include/chre/core/event.h
@@ -18,47 +18,33 @@
#define CHRE_CORE_EVENT_H_
#include "chre_api/chre/event.h"
-#include "chre/platform/assert.h"
-#include "chre/platform/log.h"
#include "chre/util/non_copyable.h"
#include <cstdint>
namespace chre {
-// TODO: put these in a more common place
+//! Instance ID used for events sent by the system
constexpr uint32_t kSystemInstanceId = 0;
+
+//! Target instance ID used to deliver a message to all nanoapps registered for
+//! the event
constexpr uint32_t kBroadcastInstanceId = UINT32_MAX;
-// Can be used in the context of a specific Nanoapp's instance ID
+//! This value can be used in a nanoapp's own instance ID to indicate that the
+//! ID is invalid/not assigned yet
constexpr uint32_t kInvalidInstanceId = kBroadcastInstanceId;
class Event : public NonCopyable {
public:
- Event(uint16_t eventType_,
- void *eventData_,
- chreEventCompleteFunction *freeCallback_,
- uint32_t senderInstanceId_ = kSystemInstanceId,
- uint32_t targetInstanceId_ = kBroadcastInstanceId)
- : eventType(eventType_),
- eventData(eventData_),
- freeCallback(freeCallback_),
- senderInstanceId(senderInstanceId_),
- targetInstanceId(targetInstanceId_) {}
+ Event(uint16_t eventType, void *eventData,
+ chreEventCompleteFunction *freeCallback,
+ uint32_t senderInstanceId = kSystemInstanceId,
+ uint32_t targetInstanceId = kBroadcastInstanceId);
- void incrementRefCount() {
- mRefCount++;
- CHRE_ASSERT(mRefCount != 0);
- }
-
- void decrementRefCount() {
- CHRE_ASSERT(mRefCount > 0);
- mRefCount--;
- }
-
- bool isUnreferenced() {
- return (mRefCount == 0);
- }
+ void incrementRefCount();
+ void decrementRefCount();
+ bool isUnreferenced() const;
const uint16_t eventType;
void * const eventData;
diff --git a/core/include/chre/core/event_loop.h b/core/include/chre/core/event_loop.h
index 1719b10..dcf4abd 100644
--- a/core/include/chre/core/event_loop.h
+++ b/core/include/chre/core/event_loop.h
@@ -73,21 +73,25 @@
void forEachNanoapp(NanoappCallbackFunction *callback, void *data);
/**
- * Starts a nanoapp by constructing a Nanoapp instance, invoking the start
- * entry point and adding it to the list of nanoapps owned by this event
- * loop.
+ * Invokes the Nanoapp's start callback, and if successful, adds it to the
+ * set of Nanoapps managed by this EventLoop. This function must only be
+ * called from the context of the thread that runs this event loop (i.e. from
+ * the same thread that will call run() or from a callback invoked within
+ * run()).
*
- * @param platformNanoapp A pointer to the platform nanoapp to start. This
- * pointer must remain valid after this function returns.
- * @return True if the app was started successfully.
+ * @param nanoapp The nanoapp that will be started. Upon success, this
+ * UniquePtr will become invalid, as the underlying Nanoapp instance
+ * will have been transferred to be managed by this EventLoop.
+ * @return true if the app was started successfully
*/
- bool startNanoapp(PlatformNanoapp *platformNanoapp);
+ bool startNanoapp(UniquePtr<Nanoapp>& nanoapp);
/**
* Stops a nanoapp by invoking the stop entry point. The nanoapp passed in
- * must have been previously started by the startNanoapp method.
+ * must have been previously started by the startNanoapp method. After this
+ * function returns, all references to the Nanoapp are invalid.
*
- * @param A pointer to the nanoapp to stop.
+ * @param nanoapp A pointer to the nanoapp to stop.
*/
void stopNanoapp(Nanoapp *nanoapp);
@@ -110,13 +114,16 @@
*
* This function is safe to call from any thread.
*
- * @param The type of data being posted.
- * @param The data being posted.
- * @param The callback to invoke when the event is no longer needed.
- * @param The instance ID of the sender of this event.
- * @param The instance ID of the destination of this event.
+ * @param eventType The type of data being posted.
+ * @param eventData The data being posted.
+ * @param freeCallback The callback to invoke when the event is no longer
+ * needed.
+ * @param senderInstanceId The instance ID of the sender of this event.
+ * @param targetInstanceId The instance ID of the destination of this event.
*
* @return true if the event was successfully added to the queue
+ *
+ * @see chreSendEvent
*/
bool postEvent(uint16_t eventType, void *eventData,
chreEventCompleteFunction *freeCallback,
@@ -141,16 +148,6 @@
size_t getNanoappCount() const;
/**
- * Returns a guaranteed unique instance ID that can be used to construct a
- * nanoapp.
- *
- * @return a unique instance ID to assign to a nanoapp.
- */
- // TODO: move this to EventLoopManager as it must be unique across all event
- // loops; we currently really only support one EventLoop so it's OK for now
- uint32_t getNextInstanceId();
-
- /**
* Obtains the TimerPool associated with this event loop.
*
* @return The timer pool owned by this event loop.
@@ -176,9 +173,6 @@
//! events are in a queue to be distributed to apps.
static constexpr size_t kMaxUnscheduledEventCount = 1024;
- //! The instance ID that was previously generated by getNextInstanceId.
- uint32_t mLastInstanceId = kSystemInstanceId;
-
//! The memory pool to allocate incoming events from.
SynchronizedMemoryPool<Event, kMaxEventCount> mEventPool;
@@ -206,6 +200,15 @@
Nanoapp *mCurrentApp = nullptr;
/**
+ * Delivers the next event pending in the Nanoapp's queue, and takes care of
+ * freeing events once they have been delivered to all nanoapps. Must only be
+ * called after confirming that the app has at least 1 pending event.
+ *
+ * @return true if the nanoapp has another event pending in its queue
+ */
+ bool deliverNextEvent(const UniquePtr<Nanoapp>& app);
+
+ /**
* Call after when an Event has been delivered to all intended recipients.
* Invokes the event's free callback (if given) and releases resources.
*
@@ -222,6 +225,11 @@
* @return Nanoapp with the given instanceId, or nullptr if not found
*/
Nanoapp *lookupAppByInstanceId(uint32_t instanceId);
+
+ /**
+ * Stops the Nanoapp at the given index in mNanoapps
+ */
+ void stopNanoapp(size_t index);
};
} // namespace chre
diff --git a/core/include/chre/core/event_loop_manager.h b/core/include/chre/core/event_loop_manager.h
index f10d0e6..fc12e34 100644
--- a/core/include/chre/core/event_loop_manager.h
+++ b/core/include/chre/core/event_loop_manager.h
@@ -43,6 +43,7 @@
WifiHandleScanEvent,
NanoappListResponse,
SensorLastEventUpdate,
+ FinishLoadingNanoapp,
};
//! The function signature of a system callback mirrors the CHRE event free
@@ -128,6 +129,14 @@
EventLoop **eventLoop = nullptr);
/**
+ * Returns a guaranteed unique instance identifier to associate with a newly
+ * constructed nanoapp.
+ *
+ * @return a unique instance ID
+ */
+ uint32_t getNextInstanceId();
+
+ /**
* Posts an event to all event loops owned by this event loop manager. This
* method is thread-safe and is used to post events that all event loops would
* be interested in, such as sensor event data.
@@ -186,6 +195,9 @@
//! of event order between event loops.
Mutex mMutex;
+ //! The instance ID that was previously generated by getNextInstanceId()
+ uint32_t mLastInstanceId = kSystemInstanceId;
+
//! The list of event loops managed by this event loop manager. The EventLoops
//! are stored in UniquePtr because they are large objects. They do not
//! provide an implementation of the move constructor so it is best left to
diff --git a/core/include/chre/core/event_ref_queue.h b/core/include/chre/core/event_ref_queue.h
index 3bacb7c..32c523b 100644
--- a/core/include/chre/core/event_ref_queue.h
+++ b/core/include/chre/core/event_ref_queue.h
@@ -14,45 +14,45 @@
* limitations under the License.
*/
-#ifndef CHRE_EVENT_QUEUE_H
-#define CHRE_EVENT_QUEUE_H
+#ifndef CHRE_EVENT_REF_QUEUE_H
+#define CHRE_EVENT_REF_QUEUE_H
#include "chre/core/event.h"
-#include "chre/platform/assert.h"
#include "chre/util/array_queue.h"
namespace chre {
/**
- * TODO
- * NOT thread-safe, non-blocking.
+ * A non-thread-safe, non-blocking wrapper around ArrayQueue that stores Event*
+ * and manages the Event reference counter.
+ * TODO: make this a template specialization? Or rework the ref count design?
*/
class EventRefQueue {
public:
- bool empty() {
- return mQueue.empty();
- }
+ ~EventRefQueue();
- bool push(Event *event) {
- CHRE_ASSERT(event != nullptr);
+ /**
+ * @return true if there are no events in the queue
+ */
+ bool empty() const;
- bool pushed = mQueue.push(event);
- if (pushed) {
- event->incrementRefCount();
- }
+ /**
+ * Adds an event to the queue, and increments its reference counter
+ *
+ * @param event The event to add
+ * @return true on success
+ */
+ bool push(Event *event);
- return pushed;
- }
-
- Event *pop() {
- CHRE_ASSERT(!mQueue.empty());
-
- Event *event = mQueue.front();
- mQueue.pop();
- event->decrementRefCount();
-
- return event;
- }
+ /**
+ * Removes the oldest event from the queue, and decrements its reference
+ * counter. Does not trigger freeing of the event if the reference count
+ * reaches 0 as a result of this function call. The queue must be non-empty as
+ * a precondition to calling this function, or undefined behavior will result.
+ *
+ * @return Pointer to the next event in the queue
+ */
+ Event *pop();
private:
//! The maximum number of events that can be outstanding for an app.
@@ -64,4 +64,4 @@
} // namespace chre
-#endif //CHRE_EVENT_QUEUE_H
+#endif // CHRE_EVENT_REF_QUEUE_H
diff --git a/core/include/chre/core/nanoapp.h b/core/include/chre/core/nanoapp.h
index 8cecb8b..ab40f30 100644
--- a/core/include/chre/core/nanoapp.h
+++ b/core/include/chre/core/nanoapp.h
@@ -23,45 +23,37 @@
#include "chre/core/event_ref_queue.h"
#include "chre/platform/platform_nanoapp.h"
#include "chre/util/dynamic_vector.h"
-#include "chre/util/non_copyable.h"
namespace chre {
/**
* A class that tracks the state of a Nanoapp including incoming events and
* event registrations.
+ *
+ * Inheritance is used to separate the common interface with common
+ * implementation part (chre::Nanoapp) from the common interface with
+ * platform-specific implementation part (chre::PlatformNanoapp) from the purely
+ * platform-specific part (chre::PlatformNanoappBase). However, this inheritance
+ * relationship does *not* imply polymorphism, and this object must only be
+ * referred to via the most-derived type, i.e. chre::Nanoapp.
*/
-class Nanoapp : public NonCopyable {
+class Nanoapp : public PlatformNanoapp {
public:
/**
- * Constructs a Nanoapp that manages the lifecycle of events and calls into
- * the entry points of the app.
- *
- * @param appId Identifies the nanoapp vendor and the app itself
- * @param appVersion An application-defined version number
- * @param targetApiVersion The CHRE API version that this app was compiled
- * against
- * @param instanceId A unique identifier for this application instance that
- * can be used to target unicast events, etc.
- * @param isSystemNanoapp true if this is a nanoapp that should not appear in
- * the list of nanoapps exposed through the context hub HAL. System
- * nanoapps can be used to leverage CHRE to implement device
- * functionality below the HAL, where the nanoapp does not communicate
- * with host-side entities through the context hub HAL.
- * @param platformNanoapp A pointer to the platform-specific nanoapp
- * functionality which allows calling the entry points and managing the
- * lifecycle of the app (such as unloading the app).
+ * @return uint32_t The globally unique identifier for this Nanoapp instance
*/
- Nanoapp(uint64_t appId, uint32_t appVersion, uint32_t targetApiVersion,
- uint32_t instanceId, bool isSystemNanoapp,
- PlatformNanoapp *platformNanoapp);
-
- uint64_t getAppId() const;
- uint32_t getAppVersion() const;
uint32_t getInstanceId() const;
- uint32_t getTargetApiVersion() const;
- bool isSystemNanoapp() const;
+ /**
+ * Assigns an instance ID to this Nanoapp. This must be called prior to
+ * starting this nanoapp.
+ */
+ void setInstanceId(uint32_t instanceId);
+
+ /**
+ * @return true if the nanoapp should receive broadcast events with the given
+ * type
+ */
bool isRegisteredForBroadcastEvent(uint16_t eventType) const;
/**
@@ -88,19 +80,6 @@
void postEvent(Event *event);
/**
- * Starts the nanoapp by invoking the start handler and returns the result of
- * the handler.
- *
- * @return True indicating that the app was started successfully.
- */
- bool start();
-
- /**
- * Stops the nanoapp by invoking the stop handler.
- */
- void stop();
-
- /**
* Indicates whether there are any pending events in this apps queue.
*
* @return True indicating that there are events available to be processed.
@@ -116,12 +95,7 @@
Event *processNextEvent();
private:
- const uint64_t mAppId;
- const uint32_t mAppVersion;
- const uint32_t mTargetApiVersion;
- const uint32_t mInstanceId;
- const bool mIsSystemNanoapp;
- PlatformNanoapp * const mPlatformNanoapp;
+ uint32_t mInstanceId = kInvalidInstanceId;
//! The set of broadcast events that this app is registered for.
// TODO: Implement a set container and replace DynamicVector here. There may
diff --git a/core/nanoapp.cc b/core/nanoapp.cc
index 3d30678..8a8e983 100644
--- a/core/nanoapp.cc
+++ b/core/nanoapp.cc
@@ -16,18 +16,20 @@
#include "chre/core/nanoapp.h"
+#include "chre/core/event_loop_manager.h"
#include "chre/platform/assert.h"
#include "chre/platform/fatal_error.h"
#include "chre/platform/log.h"
namespace chre {
-Nanoapp::Nanoapp(
- uint64_t appId, uint32_t appVersion, uint32_t targetApiVersion,
- uint32_t instanceId, bool isSystemNanoapp, PlatformNanoapp *platformNanoapp)
- : mAppId(appId), mAppVersion(appVersion),
- mTargetApiVersion(targetApiVersion), mInstanceId(instanceId),
- mIsSystemNanoapp(isSystemNanoapp), mPlatformNanoapp(platformNanoapp) {}
+uint32_t Nanoapp::getInstanceId() const {
+ return mInstanceId;
+}
+
+void Nanoapp::setInstanceId(uint32_t instanceId) {
+ mInstanceId = instanceId;
+}
bool Nanoapp::isRegisteredForBroadcastEvent(uint16_t eventType) const {
return (mRegisteredEvents.find(eventType) != mRegisteredEvents.size());
@@ -55,38 +57,10 @@
return true;
}
-uint64_t Nanoapp::getAppId() const {
- return mAppId;
-}
-
-uint32_t Nanoapp::getAppVersion() const {
- return mAppVersion;
-}
-
-uint32_t Nanoapp::getInstanceId() const {
- return mInstanceId;
-}
-
-uint32_t Nanoapp::getTargetApiVersion() const {
- return mTargetApiVersion;
-}
-
-bool Nanoapp::isSystemNanoapp() const {
- return mIsSystemNanoapp;
-}
-
void Nanoapp::postEvent(Event *event) {
mEventQueue.push(event);
}
-bool Nanoapp::start() {
- return mPlatformNanoapp->start();
-}
-
-void Nanoapp::stop() {
- mPlatformNanoapp->stop();
-}
-
bool Nanoapp::hasPendingEvent() {
return !mEventQueue.empty();
}
@@ -96,8 +70,7 @@
CHRE_ASSERT_LOG(event != nullptr, "Tried delivering event, but queue empty");
if (event != nullptr) {
- mPlatformNanoapp->handleEvent(event->senderInstanceId, event->eventType,
- event->eventData);
+ handleEvent(event->senderInstanceId, event->eventType, event->eventData);
}
return event;
diff --git a/host/common/host_protocol_host.cc b/host/common/host_protocol_host.cc
index 2f17cdd..a00ff79 100644
--- a/host/common/host_protocol_host.cc
+++ b/host/common/host_protocol_host.cc
@@ -100,6 +100,15 @@
break;
}
+ case fbs::ChreMessage::LoadNanoappResponse: {
+ const auto *resp = static_cast<const fbs::LoadNanoappResponse *>(
+ container->message());
+ fbs::LoadNanoappResponseT response;
+ resp->UnPackTo(&response);
+ handlers.handleLoadNanoappResponse(response);
+ break;
+ }
+
default:
LOGW("Got invalid/unexpected message type %" PRIu8,
static_cast<uint8_t>(container->message_type()));
@@ -112,16 +121,55 @@
void HostProtocolHost::encodeHubInfoRequest(FlatBufferBuilder& builder) {
auto request = fbs::CreateHubInfoRequest(builder);
- auto container = fbs::CreateMessageContainer(
- builder, fbs::ChreMessage::HubInfoRequest, request.Union());
- builder.Finish(container);
+ finalize(builder, fbs::ChreMessage::HubInfoRequest, request.Union());
+}
+
+void HostProtocolHost::encodeLoadNanoappRequest(
+ FlatBufferBuilder& builder, uint32_t transactionId, uint64_t appId,
+ uint32_t appVersion, uint32_t targetApiVersion,
+ const std::vector<uint8_t>& nanoappBinary) {
+ auto appBinary = builder.CreateVector(nanoappBinary);
+ auto request = fbs::CreateLoadNanoappRequest(
+ builder, transactionId, appId, appVersion, targetApiVersion, appBinary);
+ finalize(builder, fbs::ChreMessage::LoadNanoappRequest, request.Union());
}
void HostProtocolHost::encodeNanoappListRequest(FlatBufferBuilder& builder) {
auto request = fbs::CreateNanoappListRequest(builder);
- auto container = fbs::CreateMessageContainer(
- builder, fbs::ChreMessage::NanoappListRequest, request.Union());
- builder.Finish(container);
+ finalize(builder, fbs::ChreMessage::NanoappListRequest, request.Union());
+}
+
+bool HostProtocolHost::extractHostClientId(const void *message,
+ size_t messageLen,
+ uint16_t *hostClientId) {
+ bool success = verifyMessage(message, messageLen);
+
+ if (success && hostClientId != nullptr) {
+ const fbs::MessageContainer *container = fbs::GetMessageContainer(message);
+ // host_addr guaranteed to be non-null via verifyMessage (it's a required
+ // field)
+ *hostClientId = container->host_addr()->client_id();
+ success = true;
+ }
+
+ return success;
+}
+
+bool HostProtocolHost::mutateHostClientId(void *message, size_t messageLen,
+ uint16_t hostClientId) {
+ bool success = verifyMessage(message, messageLen);
+
+ if (!success) {
+ LOGE("Message verification failed - can't mutate host ID");
+ } else {
+ fbs::MessageContainer *container = fbs::GetMutableMessageContainer(message);
+ // host_addr guaranteed to be non-null via verifyMessage (it's a required
+ // field)
+ container->mutable_host_addr()->mutate_client_id(hostClientId);
+ success = true;
+ }
+
+ return success;
}
} // namespace chre
diff --git a/host/common/include/chre_host/host_messages_generated.h b/host/common/include/chre_host/host_messages_generated.h
index d23e447..4dfe1d7 100644
--- a/host/common/include/chre_host/host_messages_generated.h
+++ b/host/common/include/chre_host/host_messages_generated.h
@@ -27,6 +27,14 @@
struct NanoappListResponse;
struct NanoappListResponseT;
+struct LoadNanoappRequest;
+struct LoadNanoappRequestT;
+
+struct LoadNanoappResponse;
+struct LoadNanoappResponseT;
+
+struct HostAddress;
+
struct MessageContainer;
struct MessageContainerT;
@@ -39,8 +47,10 @@
HubInfoResponse = 3,
NanoappListRequest = 4,
NanoappListResponse = 5,
+ LoadNanoappRequest = 6,
+ LoadNanoappResponse = 7,
MIN = NONE,
- MAX = NanoappListResponse
+ MAX = LoadNanoappResponse
};
inline const char **EnumNamesChreMessage() {
@@ -51,6 +61,8 @@
"HubInfoResponse",
"NanoappListRequest",
"NanoappListResponse",
+ "LoadNanoappRequest",
+ "LoadNanoappResponse",
nullptr
};
return names;
@@ -85,6 +97,14 @@
static const ChreMessage enum_value = ChreMessage::NanoappListResponse;
};
+template<> struct ChreMessageTraits<LoadNanoappRequest> {
+ static const ChreMessage enum_value = ChreMessage::LoadNanoappRequest;
+};
+
+template<> struct ChreMessageTraits<LoadNanoappResponse> {
+ static const ChreMessage enum_value = ChreMessage::LoadNanoappResponse;
+};
+
struct ChreMessageUnion {
ChreMessage type;
flatbuffers::NativeTable *table;
@@ -130,11 +150,42 @@
return type == ChreMessage::NanoappListResponse ?
reinterpret_cast<NanoappListResponseT *>(table) : nullptr;
}
+ LoadNanoappRequestT *AsLoadNanoappRequest() {
+ return type == ChreMessage::LoadNanoappRequest ?
+ reinterpret_cast<LoadNanoappRequestT *>(table) : nullptr;
+ }
+ LoadNanoappResponseT *AsLoadNanoappResponse() {
+ return type == ChreMessage::LoadNanoappResponse ?
+ reinterpret_cast<LoadNanoappResponseT *>(table) : nullptr;
+ }
};
bool VerifyChreMessage(flatbuffers::Verifier &verifier, const void *obj, ChreMessage type);
bool VerifyChreMessageVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types);
+MANUALLY_ALIGNED_STRUCT(2) HostAddress FLATBUFFERS_FINAL_CLASS {
+ private:
+ uint16_t client_id_;
+
+ public:
+ HostAddress() {
+ memset(this, 0, sizeof(HostAddress));
+ }
+ HostAddress(const HostAddress &_o) {
+ memcpy(this, &_o, sizeof(HostAddress));
+ }
+ HostAddress(uint16_t _client_id)
+ : client_id_(flatbuffers::EndianScalar(_client_id)) {
+ }
+ uint16_t client_id() const {
+ return flatbuffers::EndianScalar(client_id_);
+ }
+ void mutate_client_id(uint16_t _client_id) {
+ flatbuffers::WriteScalar(&client_id_, _client_id);
+ }
+};
+STRUCT_END(HostAddress, 2);
+
struct NanoappMessageT : public flatbuffers::NativeTable {
typedef NanoappMessage TableType;
uint64_t app_id;
@@ -772,9 +823,216 @@
flatbuffers::Offset<NanoappListResponse> CreateNanoappListResponse(flatbuffers::FlatBufferBuilder &_fbb, const NanoappListResponseT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+struct LoadNanoappRequestT : public flatbuffers::NativeTable {
+ typedef LoadNanoappRequest TableType;
+ uint32_t transaction_id;
+ uint64_t app_id;
+ uint32_t app_version;
+ uint32_t target_api_version;
+ std::vector<uint8_t> app_binary;
+ LoadNanoappRequestT()
+ : transaction_id(0),
+ app_id(0),
+ app_version(0),
+ target_api_version(0) {
+ }
+};
+
+struct LoadNanoappRequest FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef LoadNanoappRequestT NativeTableType;
+ enum {
+ VT_TRANSACTION_ID = 4,
+ VT_APP_ID = 6,
+ VT_APP_VERSION = 8,
+ VT_TARGET_API_VERSION = 10,
+ VT_APP_BINARY = 12
+ };
+ uint32_t transaction_id() const {
+ return GetField<uint32_t>(VT_TRANSACTION_ID, 0);
+ }
+ bool mutate_transaction_id(uint32_t _transaction_id) {
+ return SetField(VT_TRANSACTION_ID, _transaction_id);
+ }
+ uint64_t app_id() const {
+ return GetField<uint64_t>(VT_APP_ID, 0);
+ }
+ bool mutate_app_id(uint64_t _app_id) {
+ return SetField(VT_APP_ID, _app_id);
+ }
+ uint32_t app_version() const {
+ return GetField<uint32_t>(VT_APP_VERSION, 0);
+ }
+ bool mutate_app_version(uint32_t _app_version) {
+ return SetField(VT_APP_VERSION, _app_version);
+ }
+ uint32_t target_api_version() const {
+ return GetField<uint32_t>(VT_TARGET_API_VERSION, 0);
+ }
+ bool mutate_target_api_version(uint32_t _target_api_version) {
+ return SetField(VT_TARGET_API_VERSION, _target_api_version);
+ }
+ const flatbuffers::Vector<uint8_t> *app_binary() const {
+ return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_APP_BINARY);
+ }
+ flatbuffers::Vector<uint8_t> *mutable_app_binary() {
+ return GetPointer<flatbuffers::Vector<uint8_t> *>(VT_APP_BINARY);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyField<uint32_t>(verifier, VT_TRANSACTION_ID) &&
+ VerifyField<uint64_t>(verifier, VT_APP_ID) &&
+ VerifyField<uint32_t>(verifier, VT_APP_VERSION) &&
+ VerifyField<uint32_t>(verifier, VT_TARGET_API_VERSION) &&
+ VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_APP_BINARY) &&
+ verifier.Verify(app_binary()) &&
+ verifier.EndTable();
+ }
+ LoadNanoappRequestT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ void UnPackTo(LoadNanoappRequestT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ static flatbuffers::Offset<LoadNanoappRequest> Pack(flatbuffers::FlatBufferBuilder &_fbb, const LoadNanoappRequestT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+};
+
+struct LoadNanoappRequestBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_transaction_id(uint32_t transaction_id) {
+ fbb_.AddElement<uint32_t>(LoadNanoappRequest::VT_TRANSACTION_ID, transaction_id, 0);
+ }
+ void add_app_id(uint64_t app_id) {
+ fbb_.AddElement<uint64_t>(LoadNanoappRequest::VT_APP_ID, app_id, 0);
+ }
+ void add_app_version(uint32_t app_version) {
+ fbb_.AddElement<uint32_t>(LoadNanoappRequest::VT_APP_VERSION, app_version, 0);
+ }
+ void add_target_api_version(uint32_t target_api_version) {
+ fbb_.AddElement<uint32_t>(LoadNanoappRequest::VT_TARGET_API_VERSION, target_api_version, 0);
+ }
+ void add_app_binary(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> app_binary) {
+ fbb_.AddOffset(LoadNanoappRequest::VT_APP_BINARY, app_binary);
+ }
+ LoadNanoappRequestBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ LoadNanoappRequestBuilder &operator=(const LoadNanoappRequestBuilder &);
+ flatbuffers::Offset<LoadNanoappRequest> Finish() {
+ const auto end = fbb_.EndTable(start_, 5);
+ auto o = flatbuffers::Offset<LoadNanoappRequest>(end);
+ fbb_.Required(o, LoadNanoappRequest::VT_APP_BINARY);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<LoadNanoappRequest> CreateLoadNanoappRequest(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ uint32_t transaction_id = 0,
+ uint64_t app_id = 0,
+ uint32_t app_version = 0,
+ uint32_t target_api_version = 0,
+ flatbuffers::Offset<flatbuffers::Vector<uint8_t>> app_binary = 0) {
+ LoadNanoappRequestBuilder builder_(_fbb);
+ builder_.add_app_id(app_id);
+ builder_.add_app_binary(app_binary);
+ builder_.add_target_api_version(target_api_version);
+ builder_.add_app_version(app_version);
+ builder_.add_transaction_id(transaction_id);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<LoadNanoappRequest> CreateLoadNanoappRequestDirect(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ uint32_t transaction_id = 0,
+ uint64_t app_id = 0,
+ uint32_t app_version = 0,
+ uint32_t target_api_version = 0,
+ const std::vector<uint8_t> *app_binary = nullptr) {
+ return chre::fbs::CreateLoadNanoappRequest(
+ _fbb,
+ transaction_id,
+ app_id,
+ app_version,
+ target_api_version,
+ app_binary ? _fbb.CreateVector<uint8_t>(*app_binary) : 0);
+}
+
+flatbuffers::Offset<LoadNanoappRequest> CreateLoadNanoappRequest(flatbuffers::FlatBufferBuilder &_fbb, const LoadNanoappRequestT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+
+struct LoadNanoappResponseT : public flatbuffers::NativeTable {
+ typedef LoadNanoappResponse TableType;
+ uint32_t transaction_id;
+ bool success;
+ LoadNanoappResponseT()
+ : transaction_id(0),
+ success(false) {
+ }
+};
+
+struct LoadNanoappResponse FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ typedef LoadNanoappResponseT NativeTableType;
+ enum {
+ VT_TRANSACTION_ID = 4,
+ VT_SUCCESS = 6
+ };
+ uint32_t transaction_id() const {
+ return GetField<uint32_t>(VT_TRANSACTION_ID, 0);
+ }
+ bool mutate_transaction_id(uint32_t _transaction_id) {
+ return SetField(VT_TRANSACTION_ID, _transaction_id);
+ }
+ bool success() const {
+ return GetField<uint8_t>(VT_SUCCESS, 0) != 0;
+ }
+ bool mutate_success(bool _success) {
+ return SetField(VT_SUCCESS, static_cast<uint8_t>(_success));
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyField<uint32_t>(verifier, VT_TRANSACTION_ID) &&
+ VerifyField<uint8_t>(verifier, VT_SUCCESS) &&
+ verifier.EndTable();
+ }
+ LoadNanoappResponseT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ void UnPackTo(LoadNanoappResponseT *_o, const flatbuffers::resolver_function_t *_resolver = nullptr) const;
+ static flatbuffers::Offset<LoadNanoappResponse> Pack(flatbuffers::FlatBufferBuilder &_fbb, const LoadNanoappResponseT* _o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+};
+
+struct LoadNanoappResponseBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_transaction_id(uint32_t transaction_id) {
+ fbb_.AddElement<uint32_t>(LoadNanoappResponse::VT_TRANSACTION_ID, transaction_id, 0);
+ }
+ void add_success(bool success) {
+ fbb_.AddElement<uint8_t>(LoadNanoappResponse::VT_SUCCESS, static_cast<uint8_t>(success), 0);
+ }
+ LoadNanoappResponseBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ LoadNanoappResponseBuilder &operator=(const LoadNanoappResponseBuilder &);
+ flatbuffers::Offset<LoadNanoappResponse> Finish() {
+ const auto end = fbb_.EndTable(start_, 2);
+ auto o = flatbuffers::Offset<LoadNanoappResponse>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<LoadNanoappResponse> CreateLoadNanoappResponse(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ uint32_t transaction_id = 0,
+ bool success = false) {
+ LoadNanoappResponseBuilder builder_(_fbb);
+ builder_.add_transaction_id(transaction_id);
+ builder_.add_success(success);
+ return builder_.Finish();
+}
+
+flatbuffers::Offset<LoadNanoappResponse> CreateLoadNanoappResponse(flatbuffers::FlatBufferBuilder &_fbb, const LoadNanoappResponseT *_o, const flatbuffers::rehasher_function_t *_rehasher = nullptr);
+
struct MessageContainerT : public flatbuffers::NativeTable {
typedef MessageContainer TableType;
ChreMessageUnion message;
+ std::unique_ptr<HostAddress> host_addr;
MessageContainerT() {
}
};
@@ -786,7 +1044,8 @@
typedef MessageContainerT NativeTableType;
enum {
VT_MESSAGE_TYPE = 4,
- VT_MESSAGE = 6
+ VT_MESSAGE = 6,
+ VT_HOST_ADDR = 8
};
ChreMessage message_type() const {
return static_cast<ChreMessage>(GetField<uint8_t>(VT_MESSAGE_TYPE, 0));
@@ -800,11 +1059,24 @@
void *mutable_message() {
return GetPointer<void *>(VT_MESSAGE);
}
+ /// The originating or destination client ID on the host side, used to direct
+ /// responses only to the client that sent the request. Although initially
+ /// populated by the requesting client, this is enforced to be the correct
+ /// value by the entity guarding access to CHRE.
+ /// This is wrapped in a struct to ensure that it is always included when
+ /// encoding the message, so it can be mutated by the host daemon.
+ const HostAddress *host_addr() const {
+ return GetStruct<const HostAddress *>(VT_HOST_ADDR);
+ }
+ HostAddress *mutable_host_addr() {
+ return GetStruct<HostAddress *>(VT_HOST_ADDR);
+ }
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyField<uint8_t>(verifier, VT_MESSAGE_TYPE) &&
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_MESSAGE) &&
VerifyChreMessage(verifier, message(), message_type()) &&
+ VerifyFieldRequired<HostAddress>(verifier, VT_HOST_ADDR) &&
verifier.EndTable();
}
MessageContainerT *UnPack(const flatbuffers::resolver_function_t *_resolver = nullptr) const;
@@ -821,15 +1093,19 @@
void add_message(flatbuffers::Offset<void> message) {
fbb_.AddOffset(MessageContainer::VT_MESSAGE, message);
}
+ void add_host_addr(const HostAddress *host_addr) {
+ fbb_.AddStruct(MessageContainer::VT_HOST_ADDR, host_addr);
+ }
MessageContainerBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
MessageContainerBuilder &operator=(const MessageContainerBuilder &);
flatbuffers::Offset<MessageContainer> Finish() {
- const auto end = fbb_.EndTable(start_, 2);
+ const auto end = fbb_.EndTable(start_, 3);
auto o = flatbuffers::Offset<MessageContainer>(end);
fbb_.Required(o, MessageContainer::VT_MESSAGE);
+ fbb_.Required(o, MessageContainer::VT_HOST_ADDR);
return o;
}
};
@@ -837,8 +1113,10 @@
inline flatbuffers::Offset<MessageContainer> CreateMessageContainer(
flatbuffers::FlatBufferBuilder &_fbb,
ChreMessage message_type = ChreMessage::NONE,
- flatbuffers::Offset<void> message = 0) {
+ flatbuffers::Offset<void> message = 0,
+ const HostAddress *host_addr = 0) {
MessageContainerBuilder builder_(_fbb);
+ builder_.add_host_addr(host_addr);
builder_.add_message(message);
builder_.add_message_type(message_type);
return builder_.Finish();
@@ -1041,6 +1319,71 @@
_nanoapps);
}
+inline LoadNanoappRequestT *LoadNanoappRequest::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
+ auto _o = new LoadNanoappRequestT();
+ UnPackTo(_o, _resolver);
+ return _o;
+}
+
+inline void LoadNanoappRequest::UnPackTo(LoadNanoappRequestT *_o, const flatbuffers::resolver_function_t *_resolver) const {
+ (void)_o;
+ (void)_resolver;
+ { auto _e = transaction_id(); _o->transaction_id = _e; };
+ { auto _e = app_id(); _o->app_id = _e; };
+ { auto _e = app_version(); _o->app_version = _e; };
+ { auto _e = target_api_version(); _o->target_api_version = _e; };
+ { auto _e = app_binary(); if (_e) for (flatbuffers::uoffset_t _i = 0; _i < _e->size(); _i++) { _o->app_binary.push_back(_e->Get(_i)); } };
+}
+
+inline flatbuffers::Offset<LoadNanoappRequest> LoadNanoappRequest::Pack(flatbuffers::FlatBufferBuilder &_fbb, const LoadNanoappRequestT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+ return CreateLoadNanoappRequest(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<LoadNanoappRequest> CreateLoadNanoappRequest(flatbuffers::FlatBufferBuilder &_fbb, const LoadNanoappRequestT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
+ (void)_rehasher;
+ (void)_o;
+ auto _transaction_id = _o->transaction_id;
+ auto _app_id = _o->app_id;
+ auto _app_version = _o->app_version;
+ auto _target_api_version = _o->target_api_version;
+ auto _app_binary = _fbb.CreateVector(_o->app_binary);
+ return chre::fbs::CreateLoadNanoappRequest(
+ _fbb,
+ _transaction_id,
+ _app_id,
+ _app_version,
+ _target_api_version,
+ _app_binary);
+}
+
+inline LoadNanoappResponseT *LoadNanoappResponse::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
+ auto _o = new LoadNanoappResponseT();
+ UnPackTo(_o, _resolver);
+ return _o;
+}
+
+inline void LoadNanoappResponse::UnPackTo(LoadNanoappResponseT *_o, const flatbuffers::resolver_function_t *_resolver) const {
+ (void)_o;
+ (void)_resolver;
+ { auto _e = transaction_id(); _o->transaction_id = _e; };
+ { auto _e = success(); _o->success = _e; };
+}
+
+inline flatbuffers::Offset<LoadNanoappResponse> LoadNanoappResponse::Pack(flatbuffers::FlatBufferBuilder &_fbb, const LoadNanoappResponseT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
+ return CreateLoadNanoappResponse(_fbb, _o, _rehasher);
+}
+
+inline flatbuffers::Offset<LoadNanoappResponse> CreateLoadNanoappResponse(flatbuffers::FlatBufferBuilder &_fbb, const LoadNanoappResponseT *_o, const flatbuffers::rehasher_function_t *_rehasher) {
+ (void)_rehasher;
+ (void)_o;
+ auto _transaction_id = _o->transaction_id;
+ auto _success = _o->success;
+ return chre::fbs::CreateLoadNanoappResponse(
+ _fbb,
+ _transaction_id,
+ _success);
+}
+
inline MessageContainerT *MessageContainer::UnPack(const flatbuffers::resolver_function_t *_resolver) const {
auto _o = new MessageContainerT();
UnPackTo(_o, _resolver);
@@ -1052,6 +1395,7 @@
(void)_resolver;
{ auto _e = message_type(); _o->message.type = _e; };
{ auto _e = message(); if (_e) _o->message.table = ChreMessageUnion::UnPack(_e, message_type(),_resolver); };
+ { auto _e = host_addr(); if (_e) _o->host_addr = std::unique_ptr<HostAddress>(new HostAddress(*_e)); };
}
inline flatbuffers::Offset<MessageContainer> MessageContainer::Pack(flatbuffers::FlatBufferBuilder &_fbb, const MessageContainerT* _o, const flatbuffers::rehasher_function_t *_rehasher) {
@@ -1063,10 +1407,12 @@
(void)_o;
auto _message_type = _o->message.type;
auto _message = _o->message.Pack(_fbb);
+ auto _host_addr = _o->host_addr ? _o->host_addr.get() : 0;
return chre::fbs::CreateMessageContainer(
_fbb,
_message_type,
- _message);
+ _message,
+ _host_addr);
}
inline bool VerifyChreMessage(flatbuffers::Verifier &verifier, const void *obj, ChreMessage type) {
@@ -1094,6 +1440,14 @@
auto ptr = reinterpret_cast<const NanoappListResponse *>(obj);
return verifier.VerifyTable(ptr);
}
+ case ChreMessage::LoadNanoappRequest: {
+ auto ptr = reinterpret_cast<const LoadNanoappRequest *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case ChreMessage::LoadNanoappResponse: {
+ auto ptr = reinterpret_cast<const LoadNanoappResponse *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
default: return false;
}
}
@@ -1131,6 +1485,14 @@
auto ptr = reinterpret_cast<const NanoappListResponse *>(obj);
return ptr->UnPack(resolver);
}
+ case ChreMessage::LoadNanoappRequest: {
+ auto ptr = reinterpret_cast<const LoadNanoappRequest *>(obj);
+ return ptr->UnPack(resolver);
+ }
+ case ChreMessage::LoadNanoappResponse: {
+ auto ptr = reinterpret_cast<const LoadNanoappResponse *>(obj);
+ return ptr->UnPack(resolver);
+ }
default: return nullptr;
}
}
@@ -1157,6 +1519,14 @@
auto ptr = reinterpret_cast<const NanoappListResponseT *>(table);
return CreateNanoappListResponse(_fbb, ptr, _rehasher).Union();
}
+ case ChreMessage::LoadNanoappRequest: {
+ auto ptr = reinterpret_cast<const LoadNanoappRequestT *>(table);
+ return CreateLoadNanoappRequest(_fbb, ptr, _rehasher).Union();
+ }
+ case ChreMessage::LoadNanoappResponse: {
+ auto ptr = reinterpret_cast<const LoadNanoappResponseT *>(table);
+ return CreateLoadNanoappResponse(_fbb, ptr, _rehasher).Union();
+ }
default: return 0;
}
}
@@ -1188,6 +1558,16 @@
delete ptr;
break;
}
+ case ChreMessage::LoadNanoappRequest: {
+ auto ptr = reinterpret_cast<LoadNanoappRequestT *>(table);
+ delete ptr;
+ break;
+ }
+ case ChreMessage::LoadNanoappResponse: {
+ auto ptr = reinterpret_cast<LoadNanoappResponseT *>(table);
+ delete ptr;
+ break;
+ }
default: break;
}
table = nullptr;
diff --git a/host/common/include/chre_host/host_protocol_host.h b/host/common/include/chre_host/host_protocol_host.h
index c6b1cd9..c11d1b7 100644
--- a/host/common/include/chre_host/host_protocol_host.h
+++ b/host/common/include/chre_host/host_protocol_host.h
@@ -48,6 +48,9 @@
virtual void handleNanoappListResponse(
const ::chre::fbs::NanoappListResponseT& response) = 0;
+
+ virtual void handleLoadNanoappResponse(
+ const ::chre::fbs::LoadNanoappResponseT& response) = 0;
};
/**
@@ -81,12 +84,51 @@
static void encodeHubInfoRequest(flatbuffers::FlatBufferBuilder& builder);
/**
+ * Encodes a message requesting to load a nanoapp specified by the included
+ * binary payload and metadata.
+ *
+ * @param builder A newly constructed FlatBufferBuilder that will be used to
+ * construct the message
+ */
+ static void encodeLoadNanoappRequest(
+ flatbuffers::FlatBufferBuilder& builder, uint32_t transactionId,
+ uint64_t appId, uint32_t appVersion, uint32_t targetApiVersion,
+ const std::vector<uint8_t>& nanoappBinary);
+
+ /**
* Encodes a message requesting the list of loaded nanoapps from CHRE
*
* @param builder A newly constructed FlatBufferBuilder that will be used to
* construct the message
*/
static void encodeNanoappListRequest(flatbuffers::FlatBufferBuilder& builder);
+
+ /**
+ * Decodes the host client ID included in the message container
+ *
+ * @param message Buffer containing a complete FlatBuffers CHRE message
+ * @param messageLen Size of the message, in bytes
+ * @param hostClientId Output parameter that will be populated with the client
+ * ID included in the message on success
+ *
+ * @return true if the host client ID was successfully decoded from the
+ * message
+ */
+ static bool extractHostClientId(const void *message, size_t messageLen,
+ uint16_t *hostClientId);
+
+ /**
+ * Update the host client ID field in the MessageContainer.
+ *
+ * @param message Buffer containing a complete FlatBuffers CHRE message
+ * @param messageLen Size of the message, in bytes
+ * @param hostClientId The value to set the host client ID to
+ *
+ * @return true if the message was verified successfully, and we were able to
+ * modify the host client ID field
+ */
+ static bool mutateHostClientId(void *message, size_t messageLen,
+ uint16_t hostClientId);
};
} // namespace chre
diff --git a/host/common/include/chre_host/socket_server.h b/host/common/include/chre_host/socket_server.h
index a14447d..5cbbdb0 100644
--- a/host/common/include/chre_host/socket_server.h
+++ b/host/common/include/chre_host/socket_server.h
@@ -43,7 +43,7 @@
* @param data Pointer to buffer containing the raw message data
* @param len Number of bytes of data received
*/
- typedef std::function<void(uint16_t clientId, const void *data, size_t len)>
+ typedef std::function<void(uint16_t clientId, void *data, size_t len)>
ClientMessageCallback;
/**
@@ -68,6 +68,18 @@
*/
void sendToAllClients(const void *data, size_t length);
+ /**
+ * Sends a message to one client, specified via its unique client ID. This
+ * method is thread-safe.
+ *
+ * @param data
+ * @param length
+ * @param clientId
+ *
+ * @return true if the message was successfully sent to the specified client
+ */
+ bool sendToClientById(const void *data, size_t length, uint16_t clientId);
+
private:
DISALLOW_COPY_AND_ASSIGN(SocketServer);
@@ -96,6 +108,8 @@
void acceptClientConnection();
void disconnectClient(int clientSocket);
void handleClientData(int clientSocket);
+ bool sendToClientSocket(const void *data, size_t length, int clientSocket,
+ uint16_t clientId);
void serviceSocket();
static std::atomic<bool> sSignalReceived;
diff --git a/host/common/socket_server.cc b/host/common/socket_server.cc
index b0d2d8a..53c5d3f 100644
--- a/host/common/socket_server.cc
+++ b/host/common/socket_server.cc
@@ -109,21 +109,12 @@
for (const auto& pair : mClients) {
int clientSocket = pair.first;
uint16_t clientId = pair.second.clientId;
-
- ssize_t bytesSent = send(clientSocket, data, length, 0);
- if (bytesSent < 0) {
- LOGE("Error sending packet of size %zu to client %" PRIu16 ": %s",
- length, clientId, strerror(errno));
- if (errno == EINTR) {
- break;
- }
- } else if (bytesSent == 0) {
- LOGW("Client %" PRIu16 " disconnected before message could be delivered",
- clientId);
- } else {
- LOGV("Delivered message of size %zu bytes to client %" PRIu16, length,
- clientId);
+ if (sendToClientSocket(data, length, clientSocket, clientId)) {
deliveredCount++;
+ } else if (errno == EINTR) {
+ // Exit early if we were interrupted - we should only get this for
+ // SIGINT/SIGTERM, so we should exit quickly
+ break;
}
}
@@ -132,6 +123,23 @@
}
}
+bool SocketServer::sendToClientById(const void *data, size_t length,
+ uint16_t clientId) {
+ std::lock_guard<std::mutex> lock(mClientsMutex);
+
+ bool sent = false;
+ for (const auto& pair : mClients) {
+ uint16_t thisClientId = pair.second.clientId;
+ if (thisClientId == clientId) {
+ int clientSocket = pair.first;
+ sent = sendToClientSocket(data, length, clientSocket, thisClientId);
+ break;
+ }
+ }
+
+ return sent;
+}
+
void SocketServer::acceptClientConnection() {
int clientSocket = accept(mSockFd, NULL, NULL);
if (clientSocket < 0) {
@@ -216,6 +224,24 @@
}
}
+bool SocketServer::sendToClientSocket(const void *data, size_t length,
+ int clientSocket, uint16_t clientId) {
+ errno = 0;
+ ssize_t bytesSent = send(clientSocket, data, length, 0);
+ if (bytesSent < 0) {
+ LOGE("Error sending packet of size %zu to client %" PRIu16 ": %s",
+ length, clientId, strerror(errno));
+ } else if (bytesSent == 0) {
+ LOGW("Client %" PRIu16 " disconnected before message could be delivered",
+ clientId);
+ } else {
+ LOGV("Delivered message of size %zu bytes to client %" PRIu16, length,
+ clientId);
+ }
+
+ return (bytesSent > 0);
+}
+
void SocketServer::serviceSocket() {
constexpr size_t kListenIndex = 0;
static_assert(kListenIndex == 0, "Code assumes that the first index is "
diff --git a/host/common/test/chre_test_client.cc b/host/common/test/chre_test_client.cc
index 0fe9c3e..d155b3f 100644
--- a/host/common/test/chre_test_client.cc
+++ b/host/common/test/chre_test_client.cc
@@ -14,6 +14,7 @@
* limitations under the License.
*/
+#include "chre/util/nanoapp/app_id.h"
#include "chre_host/host_protocol_host.h"
#include "chre_host/log.h"
#include "chre_host/socket_client.h"
@@ -22,6 +23,7 @@
#include <sys/socket.h>
#include <sys/types.h>
+#include <fstream>
#include <thread>
#include <cutils/sockets.h>
@@ -97,7 +99,7 @@
}
void handleNanoappListResponse(
- const fbs::NanoappListResponseT& response) {
+ const fbs::NanoappListResponseT& response) override {
LOGI("Got nanoapp list response with %zu apps:", response.nanoapps.size());
for (const std::unique_ptr<fbs::NanoappListEntryT>& nanoapp
: response.nanoapps) {
@@ -106,6 +108,12 @@
nanoapp->is_system);
}
}
+
+ void handleLoadNanoappResponse(
+ const ::chre::fbs::LoadNanoappResponseT& response) override {
+ LOGI("Got load nanoapp response, transaction ID 0x%" PRIx32 " result %d",
+ response.transaction_id, response.success);
+ }
};
void requestHubInfo(SocketClient& client) {
@@ -132,7 +140,8 @@
FlatBufferBuilder builder(64);
uint8_t messageData[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11};
HostProtocolHost::encodeNanoappMessage(
- builder, 0, kHostEndpoint, 1234, messageData, sizeof(messageData));
+ builder, chre::kMessageWorldAppId, kHostEndpoint, 1234, messageData,
+ sizeof(messageData));
LOGI("Sending message to nanoapp (%u bytes w/%zu bytes of payload)",
builder.GetSize(), sizeof(messageData));
@@ -141,8 +150,34 @@
}
}
+void sendLoadNanoappRequest(SocketClient& client, const char *filename) {
+ std::ifstream file(filename, std::ios::binary | std::ios::ate);
+ if (!file) {
+ LOGE("Couldn't open file '%s': %s", filename, strerror(errno));
+ return;
+ }
+ ssize_t size = file.tellg();
+ file.seekg(0, std::ios::beg);
+
+ std::vector<uint8_t> buffer(size);
+ if (!file.read(reinterpret_cast<char *>(buffer.data()), size)) {
+ LOGE("Couldn't read from file: %s", strerror(errno));
+ return;
+ }
+
+ FlatBufferBuilder builder(size + 128);
+ HostProtocolHost::encodeLoadNanoappRequest(
+ builder, 1, 0x476f6f676c00100b, 0, 0x01000000, buffer);
+
+ LOGI("Sending load nanoapp request (%u bytes total w/%zu bytes of payload)",
+ builder.GetSize(), buffer.size());
+ if (!client.sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
+ LOGE("Failed to send message");
+ }
}
+} // anonymous namespace
+
int main() {
int ret = -1;
SocketClient client;
@@ -154,6 +189,7 @@
requestHubInfo(client);
requestNanoappList(client);
sendMessageToNanoapp(client);
+ sendLoadNanoappRequest(client, "/data/activity.so");
LOGI("Sleeping, waiting on responses");
std::this_thread::sleep_for(std::chrono::seconds(5));
diff --git a/host/hal_generic/generic_context_hub.cc b/host/hal_generic/generic_context_hub.cc
index 2a7fd21..a122bea 100644
--- a/host/hal_generic/generic_context_hub.cc
+++ b/host/hal_generic/generic_context_hub.cc
@@ -15,6 +15,7 @@
*/
#define LOG_TAG "ContextHubHal"
+#define LOG_NDEBUG 0
#include "generic_context_hub.h"
@@ -31,7 +32,9 @@
namespace implementation {
using ::android::hardware::Return;
+using ::android::hardware::contexthub::V1_0::AsyncEventType;
using ::android::hardware::contexthub::V1_0::Result;
+using ::android::hardware::contexthub::V1_0::TransactionResult;
using ::android::chre::HostProtocolHost;
using ::flatbuffers::FlatBufferBuilder;
@@ -149,12 +152,30 @@
Return<Result> GenericContextHub::loadNanoApp(
uint32_t hubId, const NanoAppBinary& appBinary, uint32_t transactionId) {
- // TODO
- UNUSED(hubId);
- UNUSED(appBinary);
- UNUSED(transactionId);
+ Result result;
ALOGV("%s", __func__);
- return Result::UNKNOWN_FAILURE;
+
+ if (hubId != kDefaultHubId) {
+ result = Result::BAD_PARAMS;
+ } else {
+ FlatBufferBuilder builder(128 + appBinary.customBinary.size());
+ uint32_t targetApiVersion = (appBinary.targetChreApiMajorVersion << 24) |
+ (appBinary.targetChreApiMinorVersion << 16);
+ HostProtocolHost::encodeLoadNanoappRequest(
+ builder, transactionId, appBinary.appId, appBinary.appVersion,
+ targetApiVersion, appBinary.customBinary);
+ if (!mClient.sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
+ result = Result::UNKNOWN_FAILURE;
+ } else {
+ result = Result::OK;
+ }
+ }
+
+ ALOGD("Attempted to send load nanoapp request for app of size %zu with ID "
+ "0x%016" PRIx64 " as transaction ID %" PRIu32 ": result %" PRIu32,
+ appBinary.customBinary.size(), appBinary.appId, transactionId, result);
+
+ return result;
}
Return<Result> GenericContextHub::unloadNanoApp(
@@ -188,9 +209,21 @@
}
Return<Result> GenericContextHub::queryApps(uint32_t hubId) {
- // TODO
- UNUSED(hubId);
+ Result result;
ALOGV("%s", __func__);
+
+ if (hubId != kDefaultHubId) {
+ result = Result::BAD_PARAMS;
+ } else {
+ FlatBufferBuilder builder(64);
+ HostProtocolHost::encodeNanoappListRequest(builder);
+ if (!mClient.sendMessage(builder.GetBufferPointer(), builder.GetSize())) {
+ result = Result::UNKNOWN_FAILURE;
+ } else {
+ result = Result::OK;
+ }
+ }
+
return Result::UNKNOWN_FAILURE;
}
@@ -204,6 +237,20 @@
}
}
+void GenericContextHub::SocketCallbacks::onConnected() {
+ if (mHaveConnected) {
+ ALOGI("Reconnected to CHRE daemon");
+ if (mParent.mCallbacks != nullptr) {
+ mParent.mCallbacks->handleHubEvent(AsyncEventType::RESTARTED);
+ }
+ }
+ mHaveConnected = true;
+}
+
+void GenericContextHub::SocketCallbacks::onDisconnected() {
+ ALOGW("Lost connection to CHRE daemon");
+}
+
void GenericContextHub::SocketCallbacks::handleNanoappMessage(
uint64_t appId, uint32_t messageType, uint16_t hostEndpoint,
const void *messageData, size_t messageDataLen) {
@@ -294,6 +341,16 @@
mParent.mCallbacks->handleAppsInfo(appInfoList);
}
+void GenericContextHub::SocketCallbacks::handleLoadNanoappResponse(
+ const ::chre::fbs::LoadNanoappResponseT& response) {
+ ALOGV("Got load nanoapp response for transaction %" PRIu32 " with result %d",
+ response.transaction_id, response.success);
+
+ TransactionResult result = (response.success) ?
+ TransactionResult::SUCCESS : TransactionResult::FAILURE;
+ mParent.mCallbacks->handleTxnResult(response.transaction_id, result);
+}
+
IContexthub* HIDL_FETCH_IContexthub(const char* /* name */) {
return new GenericContextHub();
}
diff --git a/host/hal_generic/generic_context_hub.h b/host/hal_generic/generic_context_hub.h
index 2e140ef..6b3abb6 100644
--- a/host/hal_generic/generic_context_hub.h
+++ b/host/hal_generic/generic_context_hub.h
@@ -66,6 +66,8 @@
public:
SocketCallbacks(GenericContextHub& parent);
void onMessageReceived(const void *data, size_t length) override;
+ void onConnected() override;
+ void onDisconnected() override;
void handleNanoappMessage(
uint64_t appId, uint32_t messageType, uint16_t hostEndpoint,
@@ -80,8 +82,12 @@
void handleNanoappListResponse(
const ::chre::fbs::NanoappListResponseT& response) override;
+ void handleLoadNanoappResponse(
+ const ::chre::fbs::LoadNanoappResponseT& response) override;
+
private:
GenericContextHub& mParent;
+ bool mHaveConnected = false;
};
sp<SocketCallbacks> mSocketCallbacks;
diff --git a/host/msm/daemon/chre_daemon.cc b/host/msm/daemon/chre_daemon.cc
index 023e61f..9e838dd 100644
--- a/host/msm/daemon/chre_daemon.cc
+++ b/host/msm/daemon/chre_daemon.cc
@@ -40,6 +40,8 @@
* should be fully converted to C++.
*/
+#define LOG_NDEBUG 0 // TODO: for initial testing only
+
#include <ctype.h>
#include <pthread.h>
#include <stdbool.h>
@@ -50,9 +52,12 @@
#include "chre/platform/slpi/fastrpc.h"
#include "chre_host/log.h"
+#include "chre_host/host_protocol_host.h"
#include "chre_host/socket_server.h"
#include "generated/chre_slpi.h"
+using android::chre::HostProtocolHost;
+
typedef void *(thread_entry_point_f)(void *);
struct reverse_monitor_thread_data {
@@ -79,7 +84,13 @@
char line_chars[32];
int offset_chars = 0;
- LOGD("Dumping buffer of size %zu bytes", size);
+ size_t orig_size = size;
+ if (size > 128) {
+ size = 128;
+ LOGV("Dumping first 128 bytes of buffer of size %zu", orig_size);
+ } else {
+ LOGV("Dumping buffer of size %zu bytes", size);
+ }
for (size_t i = 1; i <= size; ++i) {
offset += snprintf(&line[offset], sizeof(line) - offset, "%02x ",
buffer[i - 1]);
@@ -87,7 +98,7 @@
&line_chars[offset_chars], sizeof(line_chars) - offset_chars,
"%c", (isprint(buffer[i - 1])) ? buffer[i - 1] : '.');
if ((i % 8) == 0) {
- LOGD(" %s\t%s", line, line_chars);
+ LOGV(" %s\t%s", line, line_chars);
offset = 0;
offset_chars = 0;
} else if ((i % 4) == 0) {
@@ -103,7 +114,7 @@
offset += 8;
}
*pos = '\0';
- LOGD(" %s%s%s", line, tabs, line_chars);
+ LOGV(" %s%s%s", line, tabs, line_chars);
}
}
@@ -131,7 +142,21 @@
break;
} else if (result == CHRE_FASTRPC_SUCCESS && messageLen > 0) {
log_buffer(messageBuffer, messageLen);
- server->sendToAllClients(messageBuffer, static_cast<size_t>(messageLen));
+ uint16_t hostClientId;
+ if (!HostProtocolHost::extractHostClientId(messageBuffer, messageLen,
+ &hostClientId)) {
+ LOGW("Failed to extract host client ID from message - sending "
+ "broadcast");
+ hostClientId = chre::kHostClientIdUnspecified;
+ }
+
+ if (hostClientId == chre::kHostClientIdUnspecified) {
+ server->sendToAllClients(messageBuffer,
+ static_cast<size_t>(messageLen));
+ } else {
+ server->sendToClientById(messageBuffer,
+ static_cast<size_t>(messageLen), hostClientId);
+ }
}
}
@@ -227,8 +252,7 @@
namespace {
-void onMessageReceivedFromClient(uint16_t /*clientId*/, const void *data,
- size_t length) {
+void onMessageReceivedFromClient(uint16_t clientId, void *data, size_t length) {
constexpr size_t kMaxPayloadSize = 1024 * 1024; // 1 MiB
// This limitation is due to FastRPC, but there's no case where we should come
@@ -239,6 +263,8 @@
if (length > kMaxPayloadSize) {
LOGE("Message too large to pass to SLPI (got %zu, max %zu bytes)", length,
kMaxPayloadSize);
+ } else if (!HostProtocolHost::mutateHostClientId(data, length, clientId)) {
+ LOGE("Couldn't set host client ID in message container!");
} else {
LOGD("Delivering message from host (size %zu)", length);
log_buffer(static_cast<const uint8_t *>(data), length);
diff --git a/platform/include/chre/platform/platform_nanoapp.h b/platform/include/chre/platform/platform_nanoapp.h
index f0725e4..47b78eb 100644
--- a/platform/include/chre/platform/platform_nanoapp.h
+++ b/platform/include/chre/platform/platform_nanoapp.h
@@ -19,41 +19,86 @@
#include <cstdint>
+#include "chre/util/non_copyable.h"
#include "chre/target_platform/platform_nanoapp_base.h"
namespace chre {
/**
- * An interface for calling into nanoapp entry points and managing the
- * lifecycle of a nanoapp.
- *
- * TODO: Look at unloading the app and freeing events that originate from this
- * nanoapp.
+ * The common interface to Nanoapp functionality that has platform-specific
+ * implementation but must be supported for every platform.
*/
-class PlatformNanoapp : public PlatformNanoappBase {
+class PlatformNanoapp : public PlatformNanoappBase, public NonCopyable {
public:
/**
- * Calls the start function of the nanoapp.
+ * Unloads the nanoapp from memory.
+ */
+ ~PlatformNanoapp();
+
+ /**
+ * Calls the start function of the nanoapp. For dynamically loaded nanoapps,
+ * this must also result in calling through to any of the nanoapp's static
+ * global constructors/init functions, etc., prior to invoking the
+ * nanoappStart.
*
- * @return Returns true if the app was able to start successfully.
+ * @return true if the app was able to start successfully
+ *
+ * @see nanoappStart
*/
bool start();
/**
- * Calls the handleEvent function of the nanoapp.
+ * Passes an event to the nanoapp.
*
- * @param the instance ID of the sender
- * @param the type of the event being sent
- * @param the data passed in
+ * @see nanoappHandleEvent
*/
- void handleEvent(uint32_t senderInstanceId,
- uint16_t eventType,
+ void handleEvent(uint32_t senderInstanceId, uint16_t eventType,
const void *eventData);
/**
- * Calls the stop function of the nanoapp.
+ * Calls the nanoapp's end callback. For dynamically loaded nanoapps, this
+ * must also result in calling through to any of the nanoapp's static global
+ * destructors, atexit functions, etc., after nanoappEnd returns.
+ *
+ * This function must leave the nanoapp in a state where it can be started
+ * again via start().
+ *
+ * After this function returns, the only
+ *
+ * @see nanoappEnd
*/
- void stop();
+ void end();
+
+ /**
+ * Retrieves the nanoapp's 64-bit identifier. This function must always return
+ * a valid identifier - either the one supplied by the host via the HAL (from
+ * the header), or the authoritative value inside the nanoapp binary if one
+ * exists. In the event that both are available and they do not match, the
+ * platform implementation must return false from start().
+ */
+ uint64_t getAppId() const;
+
+ /**
+ * Retrieves the nanoapp's own version number. The same restrictions apply
+ * here as for getAppId().
+ *
+ * @see #getAppId
+ */
+ uint32_t getAppVersion() const;
+
+ /**
+ * Retrieves the API version that this nanoapp was compiled against. This
+ * function must only be called while the nanoapp is running (i.e. between
+ * calls to start() and end()).
+ */
+ uint32_t getTargetApiVersion() const;
+
+ /**
+ * Returns true if the nanoapp should not appear in the context hub HAL list
+ * of nanoapps, e.g. because it implements some device functionality purely
+ * beneath the HAL.
+ */
+ bool isSystemNanoapp() const;
};
} // namespace chre
diff --git a/platform/include/chre/platform/platform_static_nanoapp_init.h b/platform/include/chre/platform/platform_static_nanoapp_init.h
deleted file mode 100644
index 3c4555f..0000000
--- a/platform/include/chre/platform/platform_static_nanoapp_init.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (C) 2017 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 CHRE_PLATFORM_PLATFORM_STATIC_NANOAPP_INIT_H_
-#define CHRE_PLATFORM_PLATFORM_STATIC_NANOAPP_INIT_H_
-
-/**
- * @file
- *
- * Includes the appropriate platform-specific header file that supplies the
- * macro to initialize a static nanoapp. The platform header file must supply the
- * following macro:
- *
- * PLATFORM_STATIC_NANOAPP_INIT(appName)
- *
- * Where appName is the name of a global variable that will be created with type
- * PlatformNanoapp.
- */
-
-#include "chre/platform/platform_nanoapp.h"
-#include "chre/target_platform/platform_static_nanoapp_init.h"
-
-#ifndef PLATFORM_STATIC_NANOAPP_INIT
-#error "PLATFORM_STATIC_NANOAPP_INIT must be defined"
-#endif // PLATFORM_STATIC_NANOAPP_INIT
-
-#endif // CHRE_PLATFORM_PLATFORM_STATIC_NANOAPP_INIT_H_
diff --git a/platform/include/chre/platform/static_nanoapp_init.h b/platform/include/chre/platform/static_nanoapp_init.h
new file mode 100644
index 0000000..c607a82
--- /dev/null
+++ b/platform/include/chre/platform/static_nanoapp_init.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2017 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 CHRE_PLATFORM_STATIC_NANOAPP_INIT_H_
+#define CHRE_PLATFORM_STATIC_NANOAPP_INIT_H_
+
+/**
+ * @file
+ * Includes the appropriate platform-specific header file that supplies the
+ * macro to initialize a static nanoapp. The platform header file must supply
+ * the following macro:
+ *
+ * CHRE_STATIC_NANOAPP_INIT(appName, appId, appVersion)
+ *
+ * Where appName is the name of a global variable that will be created with type
+ * PlatformNanoapp, appId is the app's 64-bit identifier, and appVersion is the
+ * application-defined 32-bit version number.
+ */
+
+// Since this file is included in nanoapp code, it's likely that the nanoapp log
+// macro will have been included, resulting in conflicting definitions of the
+// log macros with the ones pulled in via nanoapp.h. Undefine these macros to
+// allow their redefinition for CHRE system code.
+#ifdef CHRE_UTIL_NANOAPP_LOG_H_
+#undef LOGE
+#undef LOGW
+#undef LOGI
+#undef LOGD
+#endif // CHRE_UTIL_NANOAPP_LOG_H_
+
+#include "chre/target_platform/static_nanoapp_init.h"
+
+#ifndef CHRE_STATIC_NANOAPP_INIT
+#error "CHRE_STATIC_NANOAPP_INIT must be defined by the target platform's static_nanoapp_init.h"
+#endif
+
+#endif // CHRE_PLATFORM_STATIC_NANOAPP_INIT_H_
diff --git a/platform/shared/include/chre/platform/static_nanoapps.h b/platform/include/chre/platform/static_nanoapps.h
similarity index 95%
rename from platform/shared/include/chre/platform/static_nanoapps.h
rename to platform/include/chre/platform/static_nanoapps.h
index f2f14f7..4bbf7d0 100644
--- a/platform/shared/include/chre/platform/static_nanoapps.h
+++ b/platform/include/chre/platform/static_nanoapps.h
@@ -22,7 +22,7 @@
namespace chre {
//! The list of static nanoapps to load.
-extern PlatformNanoapp *const kStaticNanoappList[];
+extern UniquePtr<Nanoapp> *const kStaticNanoappList[];
//! The number of static nanoapps to load.
extern const size_t kStaticNanoappCount;
diff --git a/platform/linux/include/chre/target_platform/platform_nanoapp_base.h b/platform/linux/include/chre/target_platform/platform_nanoapp_base.h
index ae30ece..1dd1543 100644
--- a/platform/linux/include/chre/target_platform/platform_nanoapp_base.h
+++ b/platform/linux/include/chre/target_platform/platform_nanoapp_base.h
@@ -28,13 +28,16 @@
*/
struct PlatformNanoappBase {
//! The function pointer of the nanoapp start entry point.
- NanoappStartFunction *mStart;
+ chreNanoappStartFunction *mStart;
//! The function pointer of the nanoapp handle event entry point.
- NanoappHandleEventFunction *mHandleEvent;
+ chreNanoappHandleEventFunction *mHandleEvent;
- //! The function pointer of the nanoapp stop entry point.
- NanoappStopFunction *mStop;
+ //! The function pointer of the nanoapp end entry point.
+ chreNanoappEndFunction *mEnd;
+
+ uint64_t mAppId;
+ uint32_t mAppVersion;
};
} // namespace chre
diff --git a/platform/linux/include/chre/target_platform/static_nanoapp_init.h b/platform/linux/include/chre/target_platform/static_nanoapp_init.h
new file mode 100644
index 0000000..c9fb5bf
--- /dev/null
+++ b/platform/linux/include/chre/target_platform/static_nanoapp_init.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2017 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 CHRE_PLATFORM_LINUX_STATIC_NANOAPP_INIT_H_
+#define CHRE_PLATFORM_LINUX_STATIC_NANOAPP_INIT_H_
+
+#include "chre/core/nanoapp.h"
+#include "chre/platform/fatal_error.h"
+#include "chre/util/unique_ptr.h"
+
+/**
+ * Initializes a static nanoapp that is based on the Linux implementation of
+ * PlatformNanoappBase.
+ *
+ * @param appName the name of the nanoapp. This will be prefixed by gNanoapp
+ * when creating the global instance of the nanoapp.
+ * @param appId the app's unique 64-bit ID
+ */
+#define CHRE_STATIC_NANOAPP_INIT(appName, appId, appVersion) \
+namespace chre { \
+UniquePtr<Nanoapp> *gNanoapp##appName; \
+ \
+__attribute__((constructor)) \
+static void initializeStaticNanoapp##appName() { \
+ static UniquePtr<Nanoapp> nanoapp = MakeUnique<Nanoapp>(); \
+ if (nanoapp.isNull()) { \
+ FATAL_ERROR("Failed to allocate nanoapp " #appName); \
+ } else { \
+ nanoapp->mStart = nanoappStart; \
+ nanoapp->mHandleEvent = nanoappHandleEvent; \
+ nanoapp->mEnd = nanoappEnd; \
+ nanoapp->mAppId = appId; \
+ nanoapp->mAppVersion = appVersion; \
+ gNanoapp##appName = &nanoapp; \
+ } \
+} \
+} /* namespace chre */
+
+#endif // CHRE_PLATFORM_LINUX_STATIC_NANOAPP_INIT_H_
diff --git a/platform/shared/platform_nanoapp.cc b/platform/linux/platform_nanoapp.cc
similarity index 70%
rename from platform/shared/platform_nanoapp.cc
rename to platform/linux/platform_nanoapp.cc
index 88f6756..39266c8 100644
--- a/platform/shared/platform_nanoapp.cc
+++ b/platform/linux/platform_nanoapp.cc
@@ -14,10 +14,13 @@
* limitations under the License.
*/
+#include "chre_api/chre/version.h"
#include "chre/platform/platform_nanoapp.h"
namespace chre {
+PlatformNanoapp::~PlatformNanoapp() {}
+
bool PlatformNanoapp::start() {
return mStart();
}
@@ -28,8 +31,24 @@
mHandleEvent(senderInstanceId, eventType, eventData);
}
-void PlatformNanoapp::stop() {
- mStop();
+void PlatformNanoapp::end() {
+ mEnd();
+}
+
+uint64_t PlatformNanoapp::getAppId() const {
+ return mAppId;
+}
+
+uint32_t PlatformNanoapp::getAppVersion() const {
+ return mAppVersion;
+}
+
+uint32_t PlatformNanoapp::getTargetApiVersion() const {
+ return CHRE_API_VERSION;
+}
+
+bool PlatformNanoapp::isSystemNanoapp() const {
+ return true;
}
} // namespace chre
diff --git a/platform/linux/static_nanoapps.cc b/platform/linux/static_nanoapps.cc
index 8df55ff..817a535 100644
--- a/platform/linux/static_nanoapps.cc
+++ b/platform/linux/static_nanoapps.cc
@@ -24,15 +24,15 @@
//! The list of static nanoapps to load for the Linux platform.
__attribute__((weak))
-PlatformNanoapp *const kStaticNanoappList[] = {
- &gNanoappGnssWorld,
- &gNanoappHelloWorld,
- &gNanoappImuCal,
- &gNanoappMessageWorld,
- &gNanoappSensorWorld,
- &gNanoappTimerWorld,
- &gNanoappWifiWorld,
- &gNanoappWwanWorld,
+UniquePtr<Nanoapp> *const kStaticNanoappList[] = {
+ gNanoappGnssWorld,
+ gNanoappHelloWorld,
+ gNanoappImuCal,
+ gNanoappMessageWorld,
+ gNanoappSensorWorld,
+ gNanoappTimerWorld,
+ gNanoappWifiWorld,
+ gNanoappWwanWorld,
};
//! The size of the static nanoapp list.
diff --git a/platform/platform.mk b/platform/platform.mk
index 8389a41..f060c8e 100644
--- a/platform/platform.mk
+++ b/platform/platform.mk
@@ -34,7 +34,6 @@
HEXAGON_SRCS += platform/shared/memory.cc
HEXAGON_SRCS += platform/shared/pal_system_api.cc
HEXAGON_SRCS += platform/shared/platform_gnss.cc
-HEXAGON_SRCS += platform/shared/platform_nanoapp.cc
HEXAGON_SRCS += platform/shared/platform_sensor.cc
HEXAGON_SRCS += platform/shared/platform_wifi.cc
HEXAGON_SRCS += platform/shared/platform_wwan.cc
@@ -42,6 +41,7 @@
HEXAGON_SRCS += platform/shared/system_time.cc
HEXAGON_SRCS += platform/slpi/host_link.cc
HEXAGON_SRCS += platform/slpi/init.cc
+HEXAGON_SRCS += platform/slpi/platform_nanoapp.cc
HEXAGON_SRCS += platform/slpi/platform_sensor.cc
HEXAGON_SRCS += platform/slpi/platform_sensor_util.cc
HEXAGON_SRCS += platform/slpi/static_nanoapps.cc
@@ -60,6 +60,7 @@
X86_SRCS += platform/linux/static_nanoapps.cc
X86_SRCS += platform/linux/system_time.cc
X86_SRCS += platform/linux/system_timer.cc
+X86_SRCS += platform/linux/platform_nanoapp.cc
X86_SRCS += platform/linux/platform_sensor.cc
X86_SRCS += platform/shared/chre_api_core.cc
X86_SRCS += platform/shared/chre_api_gnss.cc
@@ -74,7 +75,6 @@
X86_SRCS += platform/shared/pal_wwan_stub.cc
X86_SRCS += platform/shared/pal_system_api.cc
X86_SRCS += platform/shared/platform_gnss.cc
-X86_SRCS += platform/shared/platform_nanoapp.cc
X86_SRCS += platform/shared/platform_sensor.cc
X86_SRCS += platform/shared/platform_wifi.cc
X86_SRCS += platform/shared/platform_wwan.cc
diff --git a/platform/shared/dso_csl_api.cc b/platform/shared/dso_csl_api.cc
deleted file mode 100644
index 5c96372..0000000
--- a/platform/shared/dso_csl_api.cc
+++ /dev/null
@@ -1,22 +0,0 @@
-/*
- * Copyright (C) 2016 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 "chre/target_platform/dso_csl_api.h"
-
-bool chreDsoCslGetApi(uint32_t apiId, void **apiHandle) {
- // TODO: implement this some time after nanoapps become DSOs
- return false;
-}
diff --git a/platform/shared/host_protocol_chre.cc b/platform/shared/host_protocol_chre.cc
index 43cc762..dccdc2b 100644
--- a/platform/shared/host_protocol_chre.cc
+++ b/platform/shared/host_protocol_chre.cc
@@ -36,6 +36,7 @@
messageLen);
} else {
const fbs::MessageContainer *container = fbs::GetMessageContainer(message);
+ uint16_t hostClientId = container->host_addr()->client_id();
switch (container->message_type()) {
case fbs::ChreMessage::NanoappMessage: {
@@ -51,13 +52,24 @@
}
case fbs::ChreMessage::HubInfoRequest:
- HostMessageHandlers::handleHubInfoRequest();
+ HostMessageHandlers::handleHubInfoRequest(hostClientId);
break;
case fbs::ChreMessage::NanoappListRequest:
- HostMessageHandlers::handleNanoappListRequest();
+ HostMessageHandlers::handleNanoappListRequest(hostClientId);
break;
+ case fbs::ChreMessage::LoadNanoappRequest: {
+ const auto *request = static_cast<const fbs::LoadNanoappRequest *>(
+ container->message());
+ const flatbuffers::Vector<uint8_t> *appBinary = request->app_binary();
+ HostMessageHandlers::handleLoadNanoappRequest(
+ hostClientId, request->transaction_id(), request->app_id(),
+ request->app_version(), request->target_api_version(),
+ appBinary->data(), appBinary->size());
+ break;
+ }
+
default:
LOGW("Got invalid/unexpected message type %" PRIu8,
static_cast<uint8_t>(container->message_type()));
@@ -73,7 +85,7 @@
const char *toolchain, uint32_t legacyPlatformVersion,
uint32_t legacyToolchainVersion, float peakMips, float stoppedPower,
float sleepPower, float peakPower, uint32_t maxMessageLen,
- uint64_t platformId, uint32_t version) {
+ uint64_t platformId, uint32_t version, uint16_t hostClientId) {
auto nameOffset = addStringAsByteVector(builder, name);
auto vendorOffset = addStringAsByteVector(builder, vendor);
auto toolchainOffset = addStringAsByteVector(builder, toolchain);
@@ -82,9 +94,8 @@
builder, nameOffset, vendorOffset, toolchainOffset, legacyPlatformVersion,
legacyToolchainVersion, peakMips, stoppedPower, sleepPower, peakPower,
maxMessageLen, platformId, version);
- auto container = fbs::CreateMessageContainer(
- builder, fbs::ChreMessage::HubInfoResponse, response.Union());
- builder.Finish(container);
+ finalize(builder, fbs::ChreMessage::HubInfoResponse, response.Union(),
+ hostClientId);
}
void HostProtocolChre::addNanoappListEntry(
@@ -100,13 +111,22 @@
void HostProtocolChre::finishNanoappListResponse(
FlatBufferBuilder& builder,
- DynamicVector<Offset<fbs::NanoappListEntry>>& offsetVector) {
+ DynamicVector<Offset<fbs::NanoappListEntry>>& offsetVector,
+ uint16_t hostClientId) {
auto vectorOffset = builder.CreateVector<Offset<fbs::NanoappListEntry>>(
offsetVector);
auto response = fbs::CreateNanoappListResponse(builder, vectorOffset);
- auto container = fbs::CreateMessageContainer(
- builder, fbs::ChreMessage::NanoappListResponse, response.Union());
- builder.Finish(container);
+ finalize(builder, fbs::ChreMessage::NanoappListResponse, response.Union(),
+ hostClientId);
+}
+
+void HostProtocolChre::encodeLoadNanoappResponse(
+ flatbuffers::FlatBufferBuilder& builder, uint16_t hostClientId,
+ uint32_t transactionId, bool success) {
+ auto response = fbs::CreateLoadNanoappResponse(builder, transactionId,
+ success);
+ finalize(builder, fbs::ChreMessage::LoadNanoappResponse, response.Union(),
+ hostClientId);
}
} // namespace chre
diff --git a/platform/shared/host_protocol_common.cc b/platform/shared/host_protocol_common.cc
index f7d187a..eab72bf 100644
--- a/platform/shared/host_protocol_common.cc
+++ b/platform/shared/host_protocol_common.cc
@@ -26,12 +26,32 @@
namespace chre {
+void HostProtocolCommon::encodeNanoappMessage(
+ FlatBufferBuilder& builder, uint64_t appId, uint32_t messageType,
+ uint16_t hostEndpoint, const void *messageData, size_t messageDataLen) {
+ auto messageDataOffset = builder.CreateVector(
+ static_cast<const uint8_t *>(messageData), messageDataLen);
+
+ auto nanoappMessage = fbs::CreateNanoappMessage(
+ builder, appId, messageType, hostEndpoint, messageDataOffset);
+ finalize(builder, fbs::ChreMessage::NanoappMessage, nanoappMessage.Union());
+}
+
Offset<Vector<int8_t>> HostProtocolCommon::addStringAsByteVector(
FlatBufferBuilder& builder, const char *str) {
return builder.CreateVector(reinterpret_cast<const int8_t *>(str),
strlen(str) + 1);
}
+void HostProtocolCommon::finalize(
+ FlatBufferBuilder& builder, fbs::ChreMessage messageType,
+ flatbuffers::Offset<void> message, uint16_t hostClientId) {
+ fbs::HostAddress hostAddr(hostClientId);
+ auto container = fbs::CreateMessageContainer(
+ builder, messageType, message, &hostAddr);
+ builder.Finish(container);
+}
+
bool HostProtocolCommon::verifyMessage(const void *message, size_t messageLen) {
bool valid = false;
@@ -45,17 +65,5 @@
return valid;
}
-void HostProtocolCommon::encodeNanoappMessage(
- FlatBufferBuilder& builder, uint64_t appId, uint32_t messageType,
- uint16_t hostEndpoint, const void *messageData, size_t messageDataLen) {
- auto messageDataOffset = builder.CreateVector(
- static_cast<const uint8_t *>(messageData), messageDataLen);
-
- auto nanoappMessage = fbs::CreateNanoappMessage(
- builder, appId, messageType, hostEndpoint, messageDataOffset);
- auto container = fbs::CreateMessageContainer(
- builder, fbs::ChreMessage::NanoappMessage, nanoappMessage.Union());
- builder.Finish(container);
-}
} // namespace chre
diff --git a/platform/shared/idl/host_messages.fbs b/platform/shared/idl/host_messages.fbs
index 30bb2fc..7472553 100644
--- a/platform/shared/idl/host_messages.fbs
+++ b/platform/shared/idl/host_messages.fbs
@@ -82,6 +82,23 @@
nanoapps:[NanoappListEntry] (required);
}
+table LoadNanoappRequest {
+ transaction_id:uint;
+
+ app_id:ulong;
+ app_version:uint;
+ target_api_version:uint;
+
+ app_binary:[ubyte] (required);
+}
+
+table LoadNanoappResponse {
+ transaction_id:uint;
+ success:bool;
+
+ // TODO: detailed error code?
+}
+
/// A union that joins together all possible messages. Note that in FlatBuffers,
/// unions have an implicit type
union ChreMessage {
@@ -93,14 +110,29 @@
NanoappListRequest,
NanoappListResponse,
+ LoadNanoappRequest,
+ LoadNanoappResponse,
+
// TODO: extend with system-specific messages, e.g. load app command, etc.
}
+struct HostAddress {
+ client_id:ushort;
+}
+
/// The top-level container that encapsulates all possible messages. Note that
/// per FlatBuffers requirements, we can't use a union as the top-level structure
/// (root type), so we must wrap it in a table.
table MessageContainer {
message:ChreMessage (required);
+
+ /// The originating or destination client ID on the host side, used to direct
+ /// responses only to the client that sent the request. Although initially
+ /// populated by the requesting client, this is enforced to be the correct
+ /// value by the entity guarding access to CHRE.
+ /// This is wrapped in a struct to ensure that it is always included when
+ /// encoding the message, so it can be mutated by the host daemon.
+ host_addr:HostAddress (required);
}
root_type MessageContainer;
diff --git a/platform/shared/include/chre/platform/shared/host_messages_generated.h b/platform/shared/include/chre/platform/shared/host_messages_generated.h
index 1d65ade..45bd73a 100644
--- a/platform/shared/include/chre/platform/shared/host_messages_generated.h
+++ b/platform/shared/include/chre/platform/shared/host_messages_generated.h
@@ -21,6 +21,12 @@
struct NanoappListResponse;
+struct LoadNanoappRequest;
+
+struct LoadNanoappResponse;
+
+struct HostAddress;
+
struct MessageContainer;
/// A union that joins together all possible messages. Note that in FlatBuffers,
@@ -32,8 +38,10 @@
HubInfoResponse = 3,
NanoappListRequest = 4,
NanoappListResponse = 5,
+ LoadNanoappRequest = 6,
+ LoadNanoappResponse = 7,
MIN = NONE,
- MAX = NanoappListResponse
+ MAX = LoadNanoappResponse
};
inline const char **EnumNamesChreMessage() {
@@ -44,6 +52,8 @@
"HubInfoResponse",
"NanoappListRequest",
"NanoappListResponse",
+ "LoadNanoappRequest",
+ "LoadNanoappResponse",
nullptr
};
return names;
@@ -78,9 +88,37 @@
static const ChreMessage enum_value = ChreMessage::NanoappListResponse;
};
+template<> struct ChreMessageTraits<LoadNanoappRequest> {
+ static const ChreMessage enum_value = ChreMessage::LoadNanoappRequest;
+};
+
+template<> struct ChreMessageTraits<LoadNanoappResponse> {
+ static const ChreMessage enum_value = ChreMessage::LoadNanoappResponse;
+};
+
bool VerifyChreMessage(flatbuffers::Verifier &verifier, const void *obj, ChreMessage type);
bool VerifyChreMessageVector(flatbuffers::Verifier &verifier, const flatbuffers::Vector<flatbuffers::Offset<void>> *values, const flatbuffers::Vector<uint8_t> *types);
+MANUALLY_ALIGNED_STRUCT(2) HostAddress FLATBUFFERS_FINAL_CLASS {
+ private:
+ uint16_t client_id_;
+
+ public:
+ HostAddress() {
+ memset(this, 0, sizeof(HostAddress));
+ }
+ HostAddress(const HostAddress &_o) {
+ memcpy(this, &_o, sizeof(HostAddress));
+ }
+ HostAddress(uint16_t _client_id)
+ : client_id_(flatbuffers::EndianScalar(_client_id)) {
+ }
+ uint16_t client_id() const {
+ return flatbuffers::EndianScalar(client_id_);
+ }
+};
+STRUCT_END(HostAddress, 2);
+
/// Represents a message sent to/from a nanoapp from/to a client on the host
struct NanoappMessage FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum {
@@ -546,13 +584,162 @@
nanoapps ? _fbb.CreateVector<flatbuffers::Offset<NanoappListEntry>>(*nanoapps) : 0);
}
+struct LoadNanoappRequest FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ enum {
+ VT_TRANSACTION_ID = 4,
+ VT_APP_ID = 6,
+ VT_APP_VERSION = 8,
+ VT_TARGET_API_VERSION = 10,
+ VT_APP_BINARY = 12
+ };
+ uint32_t transaction_id() const {
+ return GetField<uint32_t>(VT_TRANSACTION_ID, 0);
+ }
+ uint64_t app_id() const {
+ return GetField<uint64_t>(VT_APP_ID, 0);
+ }
+ uint32_t app_version() const {
+ return GetField<uint32_t>(VT_APP_VERSION, 0);
+ }
+ uint32_t target_api_version() const {
+ return GetField<uint32_t>(VT_TARGET_API_VERSION, 0);
+ }
+ const flatbuffers::Vector<uint8_t> *app_binary() const {
+ return GetPointer<const flatbuffers::Vector<uint8_t> *>(VT_APP_BINARY);
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyField<uint32_t>(verifier, VT_TRANSACTION_ID) &&
+ VerifyField<uint64_t>(verifier, VT_APP_ID) &&
+ VerifyField<uint32_t>(verifier, VT_APP_VERSION) &&
+ VerifyField<uint32_t>(verifier, VT_TARGET_API_VERSION) &&
+ VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_APP_BINARY) &&
+ verifier.Verify(app_binary()) &&
+ verifier.EndTable();
+ }
+};
+
+struct LoadNanoappRequestBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_transaction_id(uint32_t transaction_id) {
+ fbb_.AddElement<uint32_t>(LoadNanoappRequest::VT_TRANSACTION_ID, transaction_id, 0);
+ }
+ void add_app_id(uint64_t app_id) {
+ fbb_.AddElement<uint64_t>(LoadNanoappRequest::VT_APP_ID, app_id, 0);
+ }
+ void add_app_version(uint32_t app_version) {
+ fbb_.AddElement<uint32_t>(LoadNanoappRequest::VT_APP_VERSION, app_version, 0);
+ }
+ void add_target_api_version(uint32_t target_api_version) {
+ fbb_.AddElement<uint32_t>(LoadNanoappRequest::VT_TARGET_API_VERSION, target_api_version, 0);
+ }
+ void add_app_binary(flatbuffers::Offset<flatbuffers::Vector<uint8_t>> app_binary) {
+ fbb_.AddOffset(LoadNanoappRequest::VT_APP_BINARY, app_binary);
+ }
+ LoadNanoappRequestBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ LoadNanoappRequestBuilder &operator=(const LoadNanoappRequestBuilder &);
+ flatbuffers::Offset<LoadNanoappRequest> Finish() {
+ const auto end = fbb_.EndTable(start_, 5);
+ auto o = flatbuffers::Offset<LoadNanoappRequest>(end);
+ fbb_.Required(o, LoadNanoappRequest::VT_APP_BINARY);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<LoadNanoappRequest> CreateLoadNanoappRequest(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ uint32_t transaction_id = 0,
+ uint64_t app_id = 0,
+ uint32_t app_version = 0,
+ uint32_t target_api_version = 0,
+ flatbuffers::Offset<flatbuffers::Vector<uint8_t>> app_binary = 0) {
+ LoadNanoappRequestBuilder builder_(_fbb);
+ builder_.add_app_id(app_id);
+ builder_.add_app_binary(app_binary);
+ builder_.add_target_api_version(target_api_version);
+ builder_.add_app_version(app_version);
+ builder_.add_transaction_id(transaction_id);
+ return builder_.Finish();
+}
+
+inline flatbuffers::Offset<LoadNanoappRequest> CreateLoadNanoappRequestDirect(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ uint32_t transaction_id = 0,
+ uint64_t app_id = 0,
+ uint32_t app_version = 0,
+ uint32_t target_api_version = 0,
+ const std::vector<uint8_t> *app_binary = nullptr) {
+ return chre::fbs::CreateLoadNanoappRequest(
+ _fbb,
+ transaction_id,
+ app_id,
+ app_version,
+ target_api_version,
+ app_binary ? _fbb.CreateVector<uint8_t>(*app_binary) : 0);
+}
+
+struct LoadNanoappResponse FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
+ enum {
+ VT_TRANSACTION_ID = 4,
+ VT_SUCCESS = 6
+ };
+ uint32_t transaction_id() const {
+ return GetField<uint32_t>(VT_TRANSACTION_ID, 0);
+ }
+ bool success() const {
+ return GetField<uint8_t>(VT_SUCCESS, 0) != 0;
+ }
+ bool Verify(flatbuffers::Verifier &verifier) const {
+ return VerifyTableStart(verifier) &&
+ VerifyField<uint32_t>(verifier, VT_TRANSACTION_ID) &&
+ VerifyField<uint8_t>(verifier, VT_SUCCESS) &&
+ verifier.EndTable();
+ }
+};
+
+struct LoadNanoappResponseBuilder {
+ flatbuffers::FlatBufferBuilder &fbb_;
+ flatbuffers::uoffset_t start_;
+ void add_transaction_id(uint32_t transaction_id) {
+ fbb_.AddElement<uint32_t>(LoadNanoappResponse::VT_TRANSACTION_ID, transaction_id, 0);
+ }
+ void add_success(bool success) {
+ fbb_.AddElement<uint8_t>(LoadNanoappResponse::VT_SUCCESS, static_cast<uint8_t>(success), 0);
+ }
+ LoadNanoappResponseBuilder(flatbuffers::FlatBufferBuilder &_fbb)
+ : fbb_(_fbb) {
+ start_ = fbb_.StartTable();
+ }
+ LoadNanoappResponseBuilder &operator=(const LoadNanoappResponseBuilder &);
+ flatbuffers::Offset<LoadNanoappResponse> Finish() {
+ const auto end = fbb_.EndTable(start_, 2);
+ auto o = flatbuffers::Offset<LoadNanoappResponse>(end);
+ return o;
+ }
+};
+
+inline flatbuffers::Offset<LoadNanoappResponse> CreateLoadNanoappResponse(
+ flatbuffers::FlatBufferBuilder &_fbb,
+ uint32_t transaction_id = 0,
+ bool success = false) {
+ LoadNanoappResponseBuilder builder_(_fbb);
+ builder_.add_transaction_id(transaction_id);
+ builder_.add_success(success);
+ return builder_.Finish();
+}
+
/// The top-level container that encapsulates all possible messages. Note that
/// per FlatBuffers requirements, we can't use a union as the top-level structure
/// (root type), so we must wrap it in a table.
struct MessageContainer FLATBUFFERS_FINAL_CLASS : private flatbuffers::Table {
enum {
VT_MESSAGE_TYPE = 4,
- VT_MESSAGE = 6
+ VT_MESSAGE = 6,
+ VT_HOST_ADDR = 8
};
ChreMessage message_type() const {
return static_cast<ChreMessage>(GetField<uint8_t>(VT_MESSAGE_TYPE, 0));
@@ -560,11 +747,21 @@
const void *message() const {
return GetPointer<const void *>(VT_MESSAGE);
}
+ /// The originating or destination client ID on the host side, used to direct
+ /// responses only to the client that sent the request. Although initially
+ /// populated by the requesting client, this is enforced to be the correct
+ /// value by the entity guarding access to CHRE.
+ /// This is wrapped in a struct to ensure that it is always included when
+ /// encoding the message, so it can be mutated by the host daemon.
+ const HostAddress *host_addr() const {
+ return GetStruct<const HostAddress *>(VT_HOST_ADDR);
+ }
bool Verify(flatbuffers::Verifier &verifier) const {
return VerifyTableStart(verifier) &&
VerifyField<uint8_t>(verifier, VT_MESSAGE_TYPE) &&
VerifyFieldRequired<flatbuffers::uoffset_t>(verifier, VT_MESSAGE) &&
VerifyChreMessage(verifier, message(), message_type()) &&
+ VerifyFieldRequired<HostAddress>(verifier, VT_HOST_ADDR) &&
verifier.EndTable();
}
};
@@ -578,15 +775,19 @@
void add_message(flatbuffers::Offset<void> message) {
fbb_.AddOffset(MessageContainer::VT_MESSAGE, message);
}
+ void add_host_addr(const HostAddress *host_addr) {
+ fbb_.AddStruct(MessageContainer::VT_HOST_ADDR, host_addr);
+ }
MessageContainerBuilder(flatbuffers::FlatBufferBuilder &_fbb)
: fbb_(_fbb) {
start_ = fbb_.StartTable();
}
MessageContainerBuilder &operator=(const MessageContainerBuilder &);
flatbuffers::Offset<MessageContainer> Finish() {
- const auto end = fbb_.EndTable(start_, 2);
+ const auto end = fbb_.EndTable(start_, 3);
auto o = flatbuffers::Offset<MessageContainer>(end);
fbb_.Required(o, MessageContainer::VT_MESSAGE);
+ fbb_.Required(o, MessageContainer::VT_HOST_ADDR);
return o;
}
};
@@ -594,8 +795,10 @@
inline flatbuffers::Offset<MessageContainer> CreateMessageContainer(
flatbuffers::FlatBufferBuilder &_fbb,
ChreMessage message_type = ChreMessage::NONE,
- flatbuffers::Offset<void> message = 0) {
+ flatbuffers::Offset<void> message = 0,
+ const HostAddress *host_addr = 0) {
MessageContainerBuilder builder_(_fbb);
+ builder_.add_host_addr(host_addr);
builder_.add_message(message);
builder_.add_message_type(message_type);
return builder_.Finish();
@@ -626,6 +829,14 @@
auto ptr = reinterpret_cast<const NanoappListResponse *>(obj);
return verifier.VerifyTable(ptr);
}
+ case ChreMessage::LoadNanoappRequest: {
+ auto ptr = reinterpret_cast<const LoadNanoappRequest *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
+ case ChreMessage::LoadNanoappResponse: {
+ auto ptr = reinterpret_cast<const LoadNanoappResponse *>(obj);
+ return verifier.VerifyTable(ptr);
+ }
default: return false;
}
}
diff --git a/platform/shared/include/chre/platform/shared/host_protocol_chre.h b/platform/shared/include/chre/platform/shared/host_protocol_chre.h
index 737d9a8..ee2642d 100644
--- a/platform/shared/include/chre/platform/shared/host_protocol_chre.h
+++ b/platform/shared/include/chre/platform/shared/host_protocol_chre.h
@@ -37,8 +37,14 @@
uint64_t appId, uint32_t messageType, uint16_t hostEndpoint,
const void *messageData, size_t messageDataLen);
- static void handleHubInfoRequest();
- static void handleNanoappListRequest();
+ static void handleHubInfoRequest(uint16_t hostClientId);
+
+ static void handleNanoappListRequest(uint16_t hostClientId);
+
+ static void handleLoadNanoappRequest(
+ uint16_t hostClientId, uint32_t transactionId, uint64_t appId,
+ uint32_t appVersion, uint32_t targetApiVersion, const void *appBinary,
+ size_t appBinaryLen);
};
/**
@@ -70,7 +76,7 @@
const char *vendor, const char *toolchain, uint32_t legacyPlatformVersion,
uint32_t legacyToolchainVersion, float peakMips, float stoppedPower,
float sleepPower, float peakPower, uint32_t maxMessageLen,
- uint64_t platformId, uint32_t version);
+ uint64_t platformId, uint32_t version, uint16_t hostClientId);
/**
* Supports construction of a NanoappListResponse by adding a single
@@ -101,12 +107,22 @@
*
* @param builder The FlatBufferBuilder used with addNanoappListEntry()
* @param offsetVector The vector used with addNanoappListEntry()
+ * @param hostClientId
*
* @see addNanoappListEntry()
*/
static void finishNanoappListResponse(
flatbuffers::FlatBufferBuilder& builder,
- DynamicVector<NanoappListEntryOffset>& offsetVector);
+ DynamicVector<NanoappListEntryOffset>& offsetVector,
+ uint16_t hostClientId);
+
+ /**
+ * Encodes a response to the host communicating the result of dynamically
+ * loading a nanoapp.
+ */
+ static void encodeLoadNanoappResponse(
+ flatbuffers::FlatBufferBuilder& builder, uint16_t hostClientId,
+ uint32_t transactionId, bool success);
};
} // namespace chre
diff --git a/platform/shared/include/chre/platform/shared/host_protocol_common.h b/platform/shared/include/chre/platform/shared/host_protocol_common.h
index 68ec136..69e487f 100644
--- a/platform/shared/include/chre/platform/shared/host_protocol_common.h
+++ b/platform/shared/include/chre/platform/shared/host_protocol_common.h
@@ -23,6 +23,20 @@
namespace chre {
+namespace fbs {
+
+// Forward declaration of the ChreMessage enum defined in the generated
+// FlatBuffers header file
+enum class ChreMessage : uint8_t;
+
+} // namespace fbs
+
+//! On a message sent from CHRE, specifies that the host daemon should determine
+//! which client to send the message to. Usually, this is all clients, but for a
+//! message from a nanoapp, the host daemon can use the endpoint ID to determine
+//! the destination client ID.
+constexpr uint16_t kHostClientIdUnspecified = 0;
+
/**
* Functions that are shared between the CHRE and host to assist with
* communications between the two. Note that normally these functions are
@@ -48,6 +62,25 @@
static flatbuffers::Offset<flatbuffers::Vector<int8_t>>
addStringAsByteVector(flatbuffers::FlatBufferBuilder& builder,
const char *str);
+
+ /**
+ * Constructs the message container and finalizes the FlatBufferBuilder
+ *
+ * @param builder The FlatBufferBuilder that was used to construct the
+ * message prior to adding the container
+ * @param messageType Type of message that was constructed
+ * @param message Offset of the message to include (normally the return value
+ * of flatbuffers::Offset::Union() on the message offset)
+ * @param hostClientId The source/client ID of the host-side entity that
+ * sent/should receive this message. Leave unspecified (default 0)
+ * when constructing a message on the host, as this field will be
+ * set before the message is sent to CHRE.
+ */
+ static void finalize(
+ flatbuffers::FlatBufferBuilder& builder, fbs::ChreMessage messageType,
+ flatbuffers::Offset<void> message,
+ uint16_t hostClientId = kHostClientIdUnspecified);
+
static bool verifyMessage(const void *message, size_t messageLen);
};
diff --git a/platform/shared/include/chre/platform/shared/nanoapp_support_lib_dso.h b/platform/shared/include/chre/platform/shared/nanoapp_support_lib_dso.h
new file mode 100644
index 0000000..e824927
--- /dev/null
+++ b/platform/shared/include/chre/platform/shared/nanoapp_support_lib_dso.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2016 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 CHRE_PLATFORM_SHARED_NANOAPP_SUPPORT_LIB_DSO_H_
+#define CHRE_PLATFORM_SHARED_NANOAPP_SUPPORT_LIB_DSO_H_
+
+/**
+ * @file
+ * This provides the interface that the dynamic shared object (DSO) nanoapp
+ * nanoapp support library (NSL) uses to interface with the underlying CHRE
+ * implementation in a compatible manner.
+ *
+ * This header file must retain compatibility with C, and have minimal or no
+ * dependencies on other CHRE system header files, as it will be used when
+ * compiling external/dynamic nanoapps.
+ */
+
+#include "chre/util/entry_points.h"
+
+#include <stdint.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+//! Special magic value to uniquely identify the nanoapp info structure
+#define CHRE_NSL_NANOAPP_INFO_MAGIC UINT32_C(0x50e69977)
+
+//! The minor version in the nanoapp info structure helps identify whether
+#define CHRE_NSL_NANOAPP_INFO_STRUCT_MINOR_VERSION UINT8_C(0)
+
+//! The symbol name expected from the nanoapp's definition of its info struct
+#define CHRE_NSL_DSO_NANOAPP_INFO_SYMBOL_NAME "_chreNslDsoNanoappInfo"
+
+//! Maximum length of vendor and name strings
+#define CHRE_NSL_DSO_NANOAPP_STRING_MAX_LEN (32)
+
+/**
+ * DSO-based nanoapps must expose this struct under a symbol whose name is given
+ * by CHRE_NSL_DSO_NANOAPP_INFO_SYMBOL_NAME. When the nanoapp is loaded, dlsym()
+ * will be used to locate this symbol to register the nanoapp with the system.
+ */
+struct chreNslNanoappInfo {
+ //! @see CHRE_NSL_NANOAPP_INFO_MAGIC
+ uint32_t magic;
+
+ //! @see CHRE_NSL_NANOAPP_INFO_STRUCT_MINOR_VERSION
+ uint8_t structMinorVersion;
+
+ //! Set to 1 if this nanoapp is a "system nanoapp" that should not show up in
+ //! the context hub HAL, likely because it implements some device
+ //! functionality beneath the HAL.
+ uint8_t isSystemNanoapp:1;
+
+ //! Reserved for future use, set to 0. Assignment of this field to some use
+ //! must be accompanied by an increase of the struct minor version.
+ uint8_t reservedFlags:7;
+ uint8_t reserved;
+
+ //! The CHRE API version that the nanoapp was compiled against
+ uint32_t targetApiVersion;
+
+ //! A human-friendly name of the nanoapp vendor (null-terminated string,
+ //! maximum length CHRE_NSL_DSO_NANOAPP_STRING_MAX_LEN)
+ const char *vendor;
+
+ //! A human-friendly name for the nanoapp (null-terminated string, maximum
+ //! length CHRE_NSL_DSO_NANOAPP_STRING_MAX_LEN)
+ const char *name;
+
+ //! Identifies the vendor (most significant 5 bytes) and application
+ uint64_t appId;
+
+ //! Application-specific version number
+ uint32_t appVersion;
+
+ struct {
+ chreNanoappStartFunction *start;
+ chreNanoappHandleEventFunction *handleEvent;
+ chreNanoappEndFunction *end;
+ } entryPoints;
+};
+
+/**
+ * Defined as a placeholder to enable future functionality extension.
+ *
+ * @param apiId
+ * @param apiHandle If this function returns true, this will be set to a pointer
+ * to the associated structure containing the API
+ *
+ * @return true if the requested API is supported, false otherwise
+ */
+bool chreNslDsoGetApi(uint32_t apiId, void **apiHandle);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // CHRE_PLATFORM_SHARED_NANOAPP_SUPPORT_LIB_DSO_H_
diff --git a/platform/shared/include/chre/target_platform/dso_csl_api.h b/platform/shared/include/chre/target_platform/dso_csl_api.h
deleted file mode 100644
index 3d0a489..0000000
--- a/platform/shared/include/chre/target_platform/dso_csl_api.h
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * Copyright (C) 2016 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 CHRE_PLATFORM_DSO_CSL_API_H_
-#define CHRE_PLATFORM_DSO_CSL_API_H_
-
-/**
- * @file
- * This provides the interface that the dynamic shared object (DSO) nanoapp
- * client support library (CSL) uses to interface with the underlying CHRE
- * implementation in a compatible manner. These functions are not directly
- * called by the nanoapp itself, but rather the nanoapp calls CHRE APIs, which
- * are implemented in the CSL to call through to APIs retrieved via this
- * interface. While originally intended for use with the SLPI, this API can be
- * applied to any platform where the nanoapp is a dynamic module that can
- * directly call system functions, but the nanoapp does not know ahead of time
- * which functions are implemented, therefore a layer of indirection is
- * necessary to avoid unresolved symbol errors when running on older platforms.
- *
- * Note that this is *not* required to implemented/supported on all CHRE
- * platforms, only those that use the DSO CSL.
- */
-
-// TODO: sidenote - not planning on using this for Linux, at least not
-// initially... we can just implement the CHRE APIs directly and compile
-// nanoapps into the system executable for initial testing. Will need to use
-// this for SLPI, though, for compatibility reasons. And once it's used on SLPI,
-// it would make sense to have it there on Linux too, to make sure we are
-// testing apples to apples.
-
-#include <cstdint>
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct {
- // TODO: populate with references to any function calls that were not present
- // in the initial API release, or could potentially be changed in the future.
- // note that we're not completely against the nanoapp calling directly into
- // the CHRE system for things that are unlikely to change; we would just need
- // to use this method after any change happens. consider the case where we
- // have:
- // chreFoo(int x); // v1.0
- // chreFoo(int x, int y); // v1.1
- // if nanoapps called chreFoo(int) directly @ v1.0, then that version of the
- // function must be kept like that indefinitely for v1.0 apps to use. v1.1
- // apps would need to go through this indirection to call into something like
- // chreFoo_v1_1
-
- char placeholder;
-} chreSlpiCoreSystemApi;
-
-typedef struct {
- // TODO
- char placeholder;
-} chreSlpiGnssApi;
-
-typedef struct {
- // TODO
- char placeholder;
-} chreSlpiWifiApi;
-
-typedef struct {
- // TODO
- char placeholder;
-} chreSlpiWwanApi;
-
-enum chreDsoCslApiId {
- CHRE_DSO_CSL_API_ID_CORE_SYSTEM = 1,
- CHRE_DSO_CSL_API_ID_SENSORS = 2,
- CHRE_DSO_CSL_API_ID_GNSS = 3,
- CHRE_DSO_CSL_API_ID_WIFI = 4,
- CHRE_DSO_CSL_API_ID_WWAN = 5,
-};
-
-/**
- * TODO
- *
- * @param apiId
- * @param apiHandle If this function returns true, this will be set to a pointer
- * to the associated structure containing the API
- *
- * @return true if the requested API is supported, false otherwise
- */
-extern "C" bool chreDsoCslGetApi(uint32_t apiId, void **apiHandle);
-
-#ifdef __cplusplus
-}
-#endif
-
-
-#endif // CHRE_NANOAPP_API_H_
diff --git a/platform/shared/include/chre/target_platform/platform_static_nanoapp_init.h b/platform/shared/include/chre/target_platform/platform_static_nanoapp_init.h
deleted file mode 100644
index 7774124..0000000
--- a/platform/shared/include/chre/target_platform/platform_static_nanoapp_init.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2017 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 CHRE_PLATFORM_SHARED_PLATFORM_STATIC_NANOAPP_INIT_H_
-#define CHRE_PLATFORM_SHARED_PLATFORM_STATIC_NANOAPP_INIT_H_
-
-/**
- * Initializes a nanoapp that is based on the shared implementation of
- * PlatformNanoappBase.
- *
- * @param appName the name of the nanoapp. This will be prefixed by gNanoapp
- * when creating the global instance of the nanoapp.
- */
-#define PLATFORM_STATIC_NANOAPP_INIT(appName) \
-::chre::PlatformNanoapp gNanoapp##appName; \
- \
-__attribute__((constructor)) \
-static void InitializeStaticNanoapp() { \
- gNanoapp##appName.mStart = nanoappStart; \
- gNanoapp##appName.mHandleEvent = nanoappHandleEvent; \
- gNanoapp##appName.mStop = nanoappStop; \
-}
-
-#endif // CHRE_PLATFORM_SHARED_PLATFORM_STATIC_NANOAPP_INIT_H_
diff --git a/platform/shared/nanoapp/nanoapp_support_lib_dso.c b/platform/shared/nanoapp/nanoapp_support_lib_dso.c
new file mode 100644
index 0000000..8d1ab05
--- /dev/null
+++ b/platform/shared/nanoapp/nanoapp_support_lib_dso.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016 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 "chre/platform/shared/nanoapp_support_lib_dso.h"
+
+#include <chre.h>
+
+/**
+ * @file
+ * The Nanoapp Support Library (NSL) that gets built with nanoapps to act as an
+ * intermediary to the reference CHRE implementation. It provides hooks so the
+ * app can be registered with the system, and also provides a layer where we can
+ * implement cross-version compatibility features as needed.
+ */
+
+__attribute__((used)) __attribute__((visibility("default")))
+const struct chreNslNanoappInfo _chreNslDsoNanoappInfo = {
+ .magic = CHRE_NSL_NANOAPP_INFO_MAGIC,
+ .structMinorVersion = CHRE_NSL_NANOAPP_INFO_STRUCT_MINOR_VERSION,
+ .targetApiVersion = CHRE_API_VERSION,
+
+ // These values are supplied by the build environment
+ .vendor = NANOAPP_VENDOR_STRING,
+ .name = NANOAPP_NAME_STRING,
+ .isSystemNanoapp = NANOAPP_IS_SYSTEM_NANOAPP,
+ .appId = NANOAPP_ID,
+ .appVersion = NANOAPP_VERSION,
+
+ .entryPoints = {
+ .start = nanoappStart,
+ .handleEvent = nanoappHandleEvent,
+ .end = nanoappEnd,
+ },
+};
+
diff --git a/platform/shared/static_nanoapps.cc b/platform/shared/static_nanoapps.cc
index 2b5d764..eea6b9f 100644
--- a/platform/shared/static_nanoapps.cc
+++ b/platform/shared/static_nanoapps.cc
@@ -20,7 +20,7 @@
void loadStaticNanoapps(EventLoop *eventLoop) {
for (size_t i = 0; i < kStaticNanoappCount; i++) {
- eventLoop->startNanoapp(kStaticNanoappList[i]);
+ eventLoop->startNanoapp(*(kStaticNanoappList[i]));
}
}
diff --git a/platform/slpi/host_link.cc b/platform/slpi/host_link.cc
index c63ce27..39e3485 100644
--- a/platform/slpi/host_link.cc
+++ b/platform/slpi/host_link.cc
@@ -28,6 +28,7 @@
#include "chre/platform/slpi/fastrpc.h"
#include "chre/util/fixed_size_blocking_queue.h"
#include "chre/util/macros.h"
+#include "chre/util/unique_ptr.h"
#include "chre_api/chre/version.h"
using flatbuffers::FlatBufferBuilder;
@@ -38,17 +39,39 @@
constexpr size_t kOutboundQueueSize = 32;
+//! Used to pass the client ID through the user data pointer in deferCallback
+union HostClientIdCallbackData {
+ uint16_t hostClientId;
+ void *ptr;
+};
+static_assert(sizeof(uint16_t) <= sizeof(void*),
+ "Pointer must at least fit a u16 for passing the host client ID");
+
+struct LoadNanoappCallbackData {
+ uint64_t appId;
+ uint32_t transactionId;
+ uint16_t hostClientId;
+ UniquePtr<Nanoapp> nanoapp = MakeUnique<Nanoapp>();
+};
+
enum class PendingMessageType {
Shutdown,
NanoappMessageToHost,
HubInfoResponse,
NanoappListResponse,
+ LoadNanoappResponse,
};
struct PendingMessage {
- PendingMessage(PendingMessageType msgType, const void *msgData = nullptr) {
+ PendingMessage(PendingMessageType msgType, uint16_t hostClientId) {
type = msgType;
- data.data = msgData;
+ data.hostClientId = hostClientId;
+ }
+
+ PendingMessage(PendingMessageType msgType,
+ const MessageToHost *msgToHost = nullptr) {
+ type = msgType;
+ data.msgToHost = msgToHost;
}
PendingMessage(PendingMessageType msgType, FlatBufferBuilder *builder) {
@@ -59,7 +82,7 @@
PendingMessageType type;
union {
const MessageToHost *msgToHost;
- const void *data;
+ uint16_t hostClientId;
FlatBufferBuilder *builder;
} data;
};
@@ -78,7 +101,6 @@
size, bufferSize);
result = CHRE_FASTRPC_ERROR;
} else {
- LOGD("Copy %zu bytes to buffer @ %p", size, buffer);
memcpy(buffer, data, size);
*messageLen = size;
result = CHRE_FASTRPC_SUCCESS;
@@ -87,11 +109,13 @@
return result;
}
-
-void constructNanoappListCallback(uint16_t /*eventType*/, void * /*data*/) {
+void constructNanoappListCallback(uint16_t /*eventType*/, void *deferCbData) {
constexpr size_t kFixedOverhead = 56;
constexpr size_t kPerNanoappSize = 16;
+ HostClientIdCallbackData clientIdCbData;
+ clientIdCbData.ptr = deferCbData;
+
// TODO: need to add support for getting apps from multiple event loops
bool pushed = false;
EventLoop *eventLoop = getCurrentEventLoop();
@@ -125,7 +149,8 @@
// Add a NanoappListEntry to the FlatBuffer for each nanoapp
CallbackData cbData(*builder, nanoappEntries);
eventLoop->forEachNanoapp(callback, &cbData);
- HostProtocolChre::finishNanoappListResponse(*builder, nanoappEntries);
+ HostProtocolChre::finishNanoappListResponse(*builder, nanoappEntries,
+ clientIdCbData.hostClientId);
pushed = gOutboundQueue.push(
PendingMessage(PendingMessageType::NanoappListResponse, builder));
@@ -139,6 +164,33 @@
}
}
+void finishLoadingNanoappCallback(uint16_t /*eventType*/, void *data) {
+ UniquePtr<LoadNanoappCallbackData> cbData(
+ static_cast<LoadNanoappCallbackData *>(data));
+
+ EventLoop *eventLoop = getCurrentEventLoop();
+ bool startedSuccessfully = (cbData->nanoapp->isLoaded()) ?
+ eventLoop->startNanoapp(cbData->nanoapp) : false;
+
+ constexpr size_t kInitialBufferSize = 48;
+ auto *builder = memoryAlloc<FlatBufferBuilder>(kInitialBufferSize);
+ if (builder == nullptr) {
+ LOGE("Couldn't allocate memory for load nanoapp response");
+ } else {
+ HostProtocolChre::encodeLoadNanoappResponse(
+ *builder, cbData->hostClientId, cbData->transactionId,
+ startedSuccessfully);
+
+ // TODO: if this fails, ideally we should block for some timeout until
+ // there's space in the queue (like up to 1 second)
+ if (!gOutboundQueue.push(PendingMessage(
+ PendingMessageType::LoadNanoappResponse, builder))) {
+ LOGE("Couldn't push load nanoapp response to outbound queue");
+ memoryFree(builder);
+ }
+ }
+}
+
int generateMessageToHost(const MessageToHost *msgToHost, unsigned char *buffer,
size_t bufferSize, unsigned int *messageLen) {
// TODO: ideally we'd construct our flatbuffer directly in the
@@ -159,8 +211,8 @@
return result;
}
-int generateHubInfoResponse(unsigned char *buffer, size_t bufferSize,
- unsigned int *messageLen) {
+int generateHubInfoResponse(uint16_t hostClientId, unsigned char *buffer,
+ size_t bufferSize, unsigned int *messageLen) {
constexpr size_t kInitialBufferSize = 192;
constexpr char kHubName[] = "CHRE on SLPI";
@@ -184,12 +236,12 @@
builder, kHubName, kVendor, kToolchain, kLegacyPlatformVersion,
kLegacyToolchainVersion, kPeakMips, kStoppedPower, kSleepPower,
kPeakPower, CHRE_MESSAGE_TO_HOST_MAX_SIZE, chreGetPlatformId(),
- chreGetVersion());
+ chreGetVersion(), hostClientId);
return copyToHostBuffer(builder, buffer, bufferSize, messageLen);
}
-int generateNanoappListResponse(
+int generateMessageFromBuilder(
FlatBufferBuilder *builder, unsigned char *buffer, size_t bufferSize,
unsigned int *messageLen) {
CHRE_ASSERT(builder != nullptr);
@@ -235,12 +287,14 @@
break;
case PendingMessageType::HubInfoResponse:
- result = generateHubInfoResponse(buffer, bufferSize, messageLen);
+ result = generateHubInfoResponse(pendingMsg.data.hostClientId, buffer,
+ bufferSize, messageLen);
break;
case PendingMessageType::NanoappListResponse:
- result = generateNanoappListResponse(pendingMsg.data.builder,
- buffer, bufferSize, messageLen);
+ case PendingMessageType::LoadNanoappResponse:
+ result = generateMessageFromBuilder(pendingMsg.data.builder,
+ buffer, bufferSize, messageLen);
break;
default:
@@ -248,6 +302,7 @@
}
}
+ LOGD("Returning message to host (result %d length %u)", result, *messageLen);
return result;
}
@@ -334,15 +389,49 @@
appId, messageType, hostEndpoint, messageData, messageDataLen);
}
-void HostMessageHandlers::handleHubInfoRequest() {
+void HostMessageHandlers::handleHubInfoRequest(uint16_t hostClientId) {
// We generate the response in the context of chre_slpi_get_message_to_host
- gOutboundQueue.push(PendingMessage(PendingMessageType::HubInfoResponse));
+ LOGD("Got hub info request from client ID %" PRIu16, hostClientId);
+ gOutboundQueue.push(PendingMessage(
+ PendingMessageType::HubInfoResponse, hostClientId));
}
-void HostMessageHandlers::handleNanoappListRequest() {
+void HostMessageHandlers::handleNanoappListRequest(uint16_t hostClientId) {
+ LOGD("Got nanoapp list request from client ID %" PRIu16, hostClientId);
+ HostClientIdCallbackData cbData = {};
+ cbData.hostClientId = hostClientId;
EventLoopManagerSingleton::get()->deferCallback(
- SystemCallbackType::NanoappListResponse, nullptr,
+ SystemCallbackType::NanoappListResponse, cbData.ptr,
constructNanoappListCallback);
}
+void HostMessageHandlers::handleLoadNanoappRequest(
+ uint16_t hostClientId, uint32_t transactionId, uint64_t appId,
+ uint32_t appVersion, uint32_t targetApiVersion, const void *appBinary,
+ size_t appBinaryLen) {
+ auto cbData = MakeUnique<LoadNanoappCallbackData>();
+
+ LOGD("Got load nanoapp request (txnId %" PRIu32 ") for appId 0x%016" PRIx64
+ " version 0x%" PRIx32 " target API version 0x%08" PRIx32 " size %zu",
+ transactionId, appId, appVersion, targetApiVersion, appBinaryLen);
+ if (cbData.isNull() || cbData->nanoapp.isNull()) {
+ LOGE("Couldn't allocate load nanoapp callback data");
+ } else {
+ cbData->transactionId = transactionId;
+ cbData->hostClientId = hostClientId;
+ cbData->appId = appId;
+
+ // Note that if this fails, we'll generate the error response in
+ // the normal deferred callback
+ cbData->nanoapp->loadFromBuffer(appId, appVersion, appBinary, appBinaryLen);
+ if (!EventLoopManagerSingleton::get()->deferCallback(
+ SystemCallbackType::FinishLoadingNanoapp, cbData.get(),
+ finishLoadingNanoappCallback)) {
+ LOGE("Couldn't post callback to finish loading nanoapp");
+ } else {
+ cbData.release();
+ }
+ }
+}
+
} // namespace chre
diff --git a/platform/slpi/include/chre/target_platform/platform_nanoapp_base.h b/platform/slpi/include/chre/target_platform/platform_nanoapp_base.h
index cf3a381..8a0dde7 100644
--- a/platform/slpi/include/chre/target_platform/platform_nanoapp_base.h
+++ b/platform/slpi/include/chre/target_platform/platform_nanoapp_base.h
@@ -17,8 +17,10 @@
#ifndef CHRE_PLATFORM_SLPI_PLATFORM_NANOAPP_BASE_H_
#define CHRE_PLATFORM_SLPI_PLATFORM_NANOAPP_BASE_H_
+#include <cstddef>
#include <cstdint>
+#include "chre/platform/shared/nanoapp_support_lib_dso.h"
#include "chre/util/entry_points.h"
namespace chre {
@@ -26,15 +28,76 @@
/**
* SLPI-specific nanoapp functionality.
*/
-struct PlatformNanoappBase {
- //! The function pointer of the nanoapp start entry point.
- NanoappStartFunction *mStart;
+class PlatformNanoappBase {
+ public:
+ /**
+ * Copies the supplied application binary data into a new buffer. The
+ * application may be invalid - full checking and initialization happens just
+ * before invoking start() nanoapp entry point.
+ *
+ * @param appId The unique app identifier associated with this binary
+ * @param appVersion An application-defined version number
+ * @param appBinary Buffer containing the complete ELF binary for this
+ * nanoapp, without any CHRE-specific header
+ * @param appBinaryLen Size of appBinary, in bytes
+ *
+ * @return true if the allocation was successful
+ */
+ bool loadFromBuffer(uint64_t appId, uint32_t appVersion,
+ const void *appBinary, size_t appBinaryLen);
- //! The function pointer of the nanoapp handle event entry point.
- NanoappHandleEventFunction *mHandleEvent;
+ /**
+ * Associate this PlatformNanoapp with a nanoapp that is statically built into
+ * the CHRE binary with the given app info structure.
+ */
+ void loadStatic(const struct chreNslNanoappInfo *appInfo);
- //! The function pointer of the nanoapp stop entry point.
- NanoappStopFunction *mStop;
+ /**
+ * @return true if the app's binary data is resident in memory, i.e. a
+ * previous call to loadFromBuffer() or loadStatic() was successful
+ */
+ bool isLoaded() const;
+
+ protected:
+ //! The app ID we received in the metadata alongside the nanoapp binary. This
+ //! is also included in (and checked against) mAppInfo.
+ uint64_t mExpectedAppId;
+
+ //! The application-defined version number we received in the metadata
+ //! alongside the nanoapp binary. This is also included in (and checked
+ //! against) mAppInfo.
+ uint32_t mExpectedAppVersion;
+
+ //! Buffer containing the complete DSO binary
+ void *mAppBinary = nullptr;
+ size_t mAppBinaryLen = 0;
+
+ //! The dynamic shared object (DSO) handle returned by dlopen[buf]()
+ void *mDsoHandle = nullptr;
+
+ //! Pointer to the app info structure within this nanoapp
+ const struct chreNslNanoappInfo *mAppInfo = nullptr;
+
+ //! Set to true if this app is built into the CHRE binary, and was loaded via
+ //! loadStatic(). In this case, the member variables above are not valid or
+ //! applicable.
+ bool mIsStatic = false;
+
+ /**
+ * Calls dlopenbuf on the app binary, and fetches and validates the app info
+ * pointer. This will result in execution of any on-load handlers (e.g. static
+ * global constructors) in the nanoapp.
+ *
+ * @return true if the app was opened successfully and the app info structure
+ * passed validation
+ */
+ bool openNanoapp();
+
+ /**
+ * Releases the DSO handle if it was active, by calling dlclose(). This will
+ * result in execution of any unload handlers in the nanoapp.
+ */
+ void closeNanoapp();
};
} // namespace chre
diff --git a/platform/slpi/include/chre/target_platform/static_nanoapp_init.h b/platform/slpi/include/chre/target_platform/static_nanoapp_init.h
new file mode 100644
index 0000000..26bc4b2
--- /dev/null
+++ b/platform/slpi/include/chre/target_platform/static_nanoapp_init.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2017 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 CHRE_PLATFORM_SLPI_STATIC_NANOAPP_INIT_H_
+#define CHRE_PLATFORM_SLPI_STATIC_NANOAPP_INIT_H_
+
+#include "chre/core/nanoapp.h"
+#include "chre/platform/fatal_error.h"
+#include "chre/platform/shared/nanoapp_support_lib_dso.h"
+#include "chre/util/unique_ptr.h"
+
+/**
+ * Initializes a static nanoapp that is based on the SLPI implementation of
+ * PlatformNanoappBase.
+ *
+ * @param appName the name of the nanoapp. This will be prefixed by gNanoapp
+ * when creating the global instance of the nanoapp.
+ * @param appId the app's unique 64-bit ID
+ * @param appVersion the application-defined 32-bit version number
+ */
+#define CHRE_STATIC_NANOAPP_INIT(appName, appId_, appVersion_) \
+namespace chre { \
+UniquePtr<Nanoapp> *gNanoapp##appName; \
+ \
+__attribute__((constructor)) \
+static void initializeStaticNanoapp##appName() { \
+ static UniquePtr<Nanoapp> nanoapp = MakeUnique<Nanoapp>(); \
+ static struct chreNslNanoappInfo appInfo; \
+ appInfo.magic = CHRE_NSL_NANOAPP_INFO_MAGIC; \
+ appInfo.structMinorVersion = \
+ CHRE_NSL_NANOAPP_INFO_STRUCT_MINOR_VERSION; \
+ appInfo.targetApiVersion = CHRE_API_VERSION; \
+ appInfo.vendor = "Google"; /* TODO: make this configurable */\
+ appInfo.name = #appName; \
+ appInfo.isSystemNanoapp = true; \
+ appInfo.appId = appId_; \
+ appInfo.appVersion = appVersion_; \
+ appInfo.entryPoints.start = nanoappStart; \
+ appInfo.entryPoints.handleEvent = nanoappHandleEvent; \
+ appInfo.entryPoints.end = nanoappEnd; \
+ if (nanoapp.isNull()) { \
+ FATAL_ERROR("Failed to allocate nanoapp " #appName); \
+ } else { \
+ nanoapp->loadStatic(&appInfo); \
+ gNanoapp##appName = &nanoapp; \
+ } \
+} \
+} // namespace chre
+
+#endif // CHRE_PLATFORM_SLPI_STATIC_NANOAPP_INIT_H_
diff --git a/platform/slpi/platform_nanoapp.cc b/platform/slpi/platform_nanoapp.cc
new file mode 100644
index 0000000..14a6df7
--- /dev/null
+++ b/platform/slpi/platform_nanoapp.cc
@@ -0,0 +1,202 @@
+/*
+ * Copyright (C) 2017 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 "chre/platform/platform_nanoapp.h"
+
+#include "chre/platform/assert.h"
+#include "chre/platform/log.h"
+#include "chre/platform/memory.h"
+#include "chre/platform/shared/nanoapp_support_lib_dso.h"
+#include "chre_api/chre/version.h"
+
+#include "dlfcn.h"
+
+#include <inttypes.h>
+#include <string.h>
+
+namespace chre {
+
+namespace {
+
+/**
+ * Performs sanity checks on the app info structure included in a dynamically
+ * loaded nanoapp.
+ *
+ * @param expectedAppId
+ * @param expectedAppVersion
+ * @param appInfo
+ *
+ * @return true if validation was successful
+ */
+bool validateAppInfo(uint64_t expectedAppId, uint32_t expectedAppVersion,
+ const struct chreNslNanoappInfo *appInfo) {
+ uint32_t ourApiMajorVersion = CHRE_EXTRACT_MAJOR_VERSION(chreGetApiVersion());
+ uint32_t targetApiMajorVersion = CHRE_EXTRACT_MAJOR_VERSION(
+ appInfo->targetApiVersion);
+
+ bool success = false;
+ if (appInfo->magic != CHRE_NSL_NANOAPP_INFO_MAGIC) {
+ LOGE("Invalid app info magic: got 0x%08" PRIx32 " expected 0x%08" PRIx32,
+ appInfo->magic, CHRE_NSL_NANOAPP_INFO_MAGIC);
+ } else if (appInfo->appId == 0) {
+ LOGE("Rejecting invalid app ID 0");
+ } else if (expectedAppId != appInfo->appId) {
+ LOGE("Expected app ID (0x%016" PRIx64 ") doesn't match internal one (0x%016"
+ PRIx64 ")", expectedAppId, appInfo->appId);
+ } else if (expectedAppVersion != appInfo->appVersion) {
+ LOGE("Expected app version (0x%" PRIx32 ") doesn't match internal one (0x%"
+ PRIx32 ")", expectedAppVersion, appInfo->appVersion);
+ } else if (targetApiMajorVersion != ourApiMajorVersion) {
+ LOGE("App targets a different major API version (%" PRIu32 ") than what we "
+ "provide (%" PRIu32 ")", targetApiMajorVersion, ourApiMajorVersion);
+ } else if (strlen(appInfo->name) > CHRE_NSL_DSO_NANOAPP_STRING_MAX_LEN) {
+ LOGE("App name is too long");
+ } else if (strlen(appInfo->name) > CHRE_NSL_DSO_NANOAPP_STRING_MAX_LEN) {
+ LOGE("App vendor is too long");
+ } else {
+ success = true;
+ }
+
+ return success;
+}
+
+} // anonymous namespace
+
+PlatformNanoapp::~PlatformNanoapp() {
+ closeNanoapp();
+ if (mAppBinary != nullptr) {
+ memoryFree(mAppBinary);
+ }
+}
+
+bool PlatformNanoapp::start() {
+ // Invoke the start entry point after successfully opening the app
+ return (mIsStatic || openNanoapp()) ? mAppInfo->entryPoints.start() : false;
+}
+
+void PlatformNanoapp::handleEvent(uint32_t senderInstanceId,
+ uint16_t eventType,
+ const void *eventData) {
+ mAppInfo->entryPoints.handleEvent(senderInstanceId, eventType, eventData);
+}
+
+void PlatformNanoapp::end() {
+ mAppInfo->entryPoints.end();
+ closeNanoapp();
+}
+
+bool PlatformNanoappBase::loadFromBuffer(uint64_t appId, uint32_t appVersion,
+ const void *appBinary,
+ size_t appBinaryLen) {
+ CHRE_ASSERT(!isLoaded());
+ bool success = false;
+ constexpr size_t kMaxAppSize = 2 * 1024 * 1024; // 2 MiB
+
+ if (appBinaryLen > kMaxAppSize) {
+ LOGE("Rejecting app size %zu above limit %zu", appBinaryLen, kMaxAppSize);
+ } else {
+ mAppBinary = memoryAlloc(appBinaryLen);
+ if (mAppBinary == nullptr) {
+ LOGE("Couldn't allocate %zu byte buffer for nanoapp 0x%016" PRIx64,
+ appBinaryLen, appId);
+ } else {
+ mExpectedAppId = appId;
+ mExpectedAppVersion = appVersion;
+ mAppBinaryLen = appBinaryLen;
+ memcpy(mAppBinary, appBinary, appBinaryLen);
+ success = true;
+ }
+ }
+
+ return success;
+}
+
+void PlatformNanoappBase::loadStatic(const struct chreNslNanoappInfo *appInfo) {
+ CHRE_ASSERT(!isLoaded());
+ mIsStatic = true;
+ mAppInfo = appInfo;
+}
+
+bool PlatformNanoappBase::isLoaded() const {
+ return (mIsStatic || mAppBinary != nullptr);
+}
+
+void PlatformNanoappBase::closeNanoapp() {
+ if (mDsoHandle != nullptr) {
+ if (dlclose(mDsoHandle) != 0) {
+ const char *name = (mAppInfo != nullptr) ? mAppInfo->name : "unknown";
+ LOGE("dlclose of %s failed: %s", name, dlerror());
+ }
+ mDsoHandle = nullptr;
+ }
+}
+
+bool PlatformNanoappBase::openNanoapp() {
+ bool success = false;
+
+ // Populate a filename string (just a requirement of the dlopenbuf API)
+ constexpr size_t kMaxFilenameLen = 17;
+ char filename[kMaxFilenameLen];
+ snprintf(filename, sizeof(filename), "%016" PRIx64, mExpectedAppId);
+
+ CHRE_ASSERT(mAppBinary != nullptr);
+ CHRE_ASSERT_LOG(mDsoHandle == nullptr, "Re-opening nanoapp");
+ mDsoHandle = dlopenbuf(
+ filename, static_cast<const char *>(mAppBinary),
+ static_cast<int>(mAppBinaryLen), RTLD_NOW);
+ if (mDsoHandle == nullptr) {
+ LOGE("Failed to load nanoapp: %s", dlerror());
+ } else {
+ mAppInfo = static_cast<const struct chreNslNanoappInfo *>(
+ dlsym(mDsoHandle, CHRE_NSL_DSO_NANOAPP_INFO_SYMBOL_NAME));
+ if (mAppInfo == nullptr) {
+ LOGE("Failed to find app info symbol: %s", dlerror());
+ } else {
+ success = validateAppInfo(mExpectedAppId, mExpectedAppVersion, mAppInfo);
+ if (!success) {
+ mAppInfo = nullptr;
+ } else {
+ LOGI("Successfully loaded nanoapp: %s (0x%016" PRIx64 ") version 0x%"
+ PRIx32, mAppInfo->name, mAppInfo->appId, mAppInfo->appVersion);
+ }
+ }
+ }
+
+ return success;
+}
+
+uint64_t PlatformNanoapp::getAppId() const {
+ return (mAppInfo != nullptr) ? mAppInfo->appId : mExpectedAppId;
+}
+
+uint32_t PlatformNanoapp::getAppVersion() const {
+ return (mAppInfo != nullptr) ? mAppInfo->appVersion : mExpectedAppVersion;
+}
+
+uint32_t PlatformNanoapp::getTargetApiVersion() const {
+ return (mAppInfo != nullptr) ? mAppInfo->targetApiVersion : 0;
+}
+
+bool PlatformNanoapp::isSystemNanoapp() const {
+ // Right now, we assume that system nanoapps are always static nanoapps. Since
+ // mAppInfo can only be null either prior to loading the app (in which case
+ // this function is not expected to return a valid value anyway), or when a
+ // dynamic nanoapp is not running, "false" is the correct return value in that
+ // case.
+ return (mAppInfo != nullptr) ? mAppInfo->isSystemNanoapp : false;
+}
+
+} // namespace chre
diff --git a/platform/slpi/static_nanoapps.cc b/platform/slpi/static_nanoapps.cc
index 17368ad..f3ac3d0 100644
--- a/platform/slpi/static_nanoapps.cc
+++ b/platform/slpi/static_nanoapps.cc
@@ -26,15 +26,15 @@
//! disabled by default, uncomment them as needed for local testing. This is
//! supplied as a weak symbol so that device builds can override this list.
__attribute__((weak))
-PlatformNanoapp *const kStaticNanoappList[] = {
-// &gNanoappGnssWorld,
-// &gNanoappHelloWorld,
-// &gNanoappImuCal,
-// &gNanoappMessageWorld,
-// &gNanoappSensorWorld,
-// &gNanoappTimerWorld,
-// &gNanoappWifiWorld,
-// &gNanoappWwanWorld,
+UniquePtr<Nanoapp> *const kStaticNanoappList[] = {
+// gNanoappGnssWorld,
+// gNanoappHelloWorld,
+// gNanoappImuCal,
+// gNanoappMessageWorld,
+// gNanoappSensorWorld,
+// gNanoappTimerWorld,
+// gNanoappWifiWorld,
+// gNanoappWwanWorld,
};
//! The size of the static nanoapp list.
diff --git a/util/include/chre/util/array_queue.h b/util/include/chre/util/array_queue.h
index fc4f9c2..d92532c 100644
--- a/util/include/chre/util/array_queue.h
+++ b/util/include/chre/util/array_queue.h
@@ -97,14 +97,15 @@
const ElementType& operator[](size_t index) const;
/**
- * Pushes an element onto the back of the array queue. It returns false if
- * the array queue is full already and there is no room for the elements. All
- * iterators and references are unaffected.
+ * Pushes an element onto the back of the array queue via copy or move
+ * construction. It returns false if the array queue is full already and there
+ * is no room for the elements. All iterators and references are unaffected.
*
* @param element The element to push onto the array queue.
* @return true if the element is pushed successfully.
*/
bool push(const ElementType& element);
+ bool push(ElementType&& element);
/**
* Removes the front element from the array queue if the array queue is not
diff --git a/util/include/chre/util/array_queue_impl.h b/util/include/chre/util/array_queue_impl.h
index e5ede30..2d3061e 100644
--- a/util/include/chre/util/array_queue_impl.h
+++ b/util/include/chre/util/array_queue_impl.h
@@ -17,6 +17,7 @@
#ifndef CHRE_UTIL_ARRAY_QUEUE_IMPL_H_
#define CHRE_UTIL_ARRAY_QUEUE_IMPL_H_
+#include <new>
#include <utility>
#include "chre/platform/assert.h"
@@ -75,7 +76,16 @@
bool ArrayQueue<ElementType, kCapacity>::push(const ElementType& element) {
bool success = pushTail();
if (success) {
- data()[mTail] = element;
+ new (&data()[mTail]) ElementType(element);
+ }
+ return success;
+}
+
+template<typename ElementType, size_t kCapacity>
+bool ArrayQueue<ElementType, kCapacity>::push(ElementType&& element) {
+ bool success = pushTail();
+ if (success) {
+ new (&data()[mTail]) ElementType(std::move(element));
}
return success;
}
diff --git a/util/include/chre/util/dynamic_vector.h b/util/include/chre/util/dynamic_vector.h
index ce0d770..2e8bb0f 100644
--- a/util/include/chre/util/dynamic_vector.h
+++ b/util/include/chre/util/dynamic_vector.h
@@ -95,25 +95,15 @@
bool empty() const;
/**
- * Pushes an element onto the back of the vector. If the vector requires a
- * resize and that allocation fails this function will return false. All
- * iterators and references are invalidated if the container has been
- * resized. Otherwise, only the past-the-end iterator is invalidated.
+ * Copy- or move-constructs an element onto the back of the vector. If the
+ * vector requires a resize and that allocation fails this function will
+ * return false. All iterators and references are invalidated if the container
+ * has been resized. Otherwise, only the past-the-end iterator is invalidated.
*
* @param The element to push onto the vector.
* @return true if the element was pushed successfully.
*/
bool push_back(const ElementType& element);
-
- /**
- * Moves an element onto the back of the vector. If the vector requires a
- * resize and that allocation fails this function will return false. All
- * iterators and references are invalidated if the container has been
- * resized. Otherwise, only the past-the-end iterator is invalidated.
- *
- * @param The element to move onto the vector.
- * @return true if the element was moved successfully.
- */
bool push_back(ElementType&& element);
/**
@@ -178,6 +168,7 @@
* @return Whether or not the insert operation was successful.
*/
bool insert(size_t index, const ElementType& element);
+ bool insert(size_t index, ElementType&& element);
/**
* Similar to wrap(), except makes a copy of the supplied C-style array,
@@ -348,6 +339,15 @@
//! Set to true when the buffer (mData) was supplied via wrap()
bool mDataIsWrapped = false;
+
+ /**
+ * Prepares the vector for insertion - upon successful return, the memory at
+ * the given index will be allocated but uninitialized
+ *
+ * @param index
+ * @return true
+ */
+ bool prepareInsert(size_t index);
};
} // namespace chre
diff --git a/util/include/chre/util/dynamic_vector_impl.h b/util/include/chre/util/dynamic_vector_impl.h
index 2585650..633a459 100644
--- a/util/include/chre/util/dynamic_vector_impl.h
+++ b/util/include/chre/util/dynamic_vector_impl.h
@@ -17,12 +17,13 @@
#ifndef CHRE_UTIL_DYNAMIC_VECTOR_IMPL_H_
#define CHRE_UTIL_DYNAMIC_VECTOR_IMPL_H_
-#include <algorithm>
+#include <memory>
+#include <new>
#include <utility>
#include "chre/platform/assert.h"
#include "chre/platform/memory.h"
-#include "chre/util/dynamic_vector.h"
+#include "chre/util/memory.h"
namespace chre {
@@ -51,9 +52,7 @@
template <typename ElementType>
void DynamicVector<ElementType>::clear() {
- for (size_t i = 0; i < mSize; i++) {
- mData[i].~ElementType();
- }
+ destroy(mData, mSize);
mSize = 0;
}
@@ -86,7 +85,7 @@
bool DynamicVector<ElementType>::push_back(const ElementType& element) {
bool spaceAvailable = prepareForPush();
if (spaceAvailable) {
- mData[mSize++] = element;
+ new (&mData[mSize++]) ElementType(element);
}
return spaceAvailable;
@@ -96,7 +95,7 @@
bool DynamicVector<ElementType>::push_back(ElementType&& element) {
bool spaceAvailable = prepareForPush();
if (spaceAvailable) {
- mData[mSize++] = std::move(element);
+ new (&mData[mSize++]) ElementType(std::move(element));
}
return spaceAvailable;
@@ -133,34 +132,6 @@
return data()[index];
}
-/**
- * Moves a range of data items. This is part of the template specialization for
- * when the underlying type is move-assignable.
- *
- * @param data The beginning of the data to move.
- * @param count The number of data items to move.
- * @param newData The location to move these items to.
- */
-template<typename ElementType>
-void moveOrCopy(ElementType *data, size_t count, ElementType *newData,
- std::true_type) {
- std::move(data, data + count, newData);
-}
-
-/**
- * Copies a range of data items. This is part of the template specialization
- * for when the underlying type is not move-assignable.
- *
- * @param data The beginning of the data to copy.
- * @param count The number of data items to copy.
- * @param newData The location to copy these items to.
- */
-template<typename ElementType>
-void moveOrCopy(ElementType *data, size_t count, ElementType *newData,
- std::false_type) {
- std::copy(data, data + count, newData);
-}
-
template<typename ElementType>
bool DynamicVector<ElementType>::reserve(size_t newCapacity) {
bool success = false;
@@ -172,9 +143,8 @@
ElementType *newData = static_cast<ElementType *>(
memoryAlloc(newCapacity * sizeof(ElementType)));
if (newData != nullptr) {
- moveOrCopy(mData, mSize, newData,
- typename std::is_move_assignable<ElementType>::type());
-
+ uninitializedMoveOrCopy(mData, mSize, newData);
+ destroy(mData, mSize);
memoryFree(mData);
mData = newData;
mCapacity = newCapacity;
@@ -188,24 +158,48 @@
template<typename ElementType>
bool DynamicVector<ElementType>::insert(size_t index,
const ElementType& element) {
+ bool inserted = prepareInsert(index);
+ if (inserted) {
+ new (&mData[index]) ElementType(element);
+ }
+ return inserted;
+}
+
+template<typename ElementType>
+bool DynamicVector<ElementType>::insert(size_t index, ElementType&& element) {
+ bool inserted = prepareInsert(index);
+ if (inserted) {
+ new (&mData[index]) ElementType(std::move(element));
+ }
+ return inserted;
+}
+
+template<typename ElementType>
+bool DynamicVector<ElementType>::prepareInsert(size_t index) {
// Insertions are not allowed to create a sparse array.
CHRE_ASSERT(index <= mSize);
- bool inserted = false;
- if (index <= mSize && prepareForPush()) {
- // Shift all elements starting at the given index backward one position.
- for (size_t i = mSize; i > index; i--) {
- mData[i] = std::move(mData[i - 1]);
+ // TODO: this can be optimized in the case where we need to grow the vector to
+ // do the shift when transferring the values from the old array to the new.
+ bool readyForInsert = (index <= mSize && prepareForPush());
+ if (readyForInsert) {
+ // If we aren't simply appending the new object, create an opening where
+ // we'll insert it
+ if (index < mSize) {
+ // Make a duplicate of the last item in the slot where we're growing
+ uninitializedMoveOrCopy(&mData[mSize - 1], 1, &mData[mSize]);
+ // Shift all elements starting at index towards the end
+ for (size_t i = mSize - 1; i > index; i--) {
+ moveOrCopyAssign(mData[i], mData[i - 1]);
+ }
+
+ mData[index].~ElementType();
}
- mData[index].~ElementType();
- mData[index] = element;
mSize++;
-
- inserted = true;
}
- return inserted;
+ return readyForInsert;
}
template<typename ElementType>
@@ -230,7 +224,7 @@
if (index < mSize) {
mSize--;
for (size_t i = index; i < mSize; i++) {
- mData[i] = std::move(mData[i + 1]);
+ moveOrCopyAssign(mData[i], mData[i + 1]);
}
mData[mSize].~ElementType();
@@ -253,10 +247,13 @@
template<typename ElementType>
void DynamicVector<ElementType>::swap(size_t index0, size_t index1) {
CHRE_ASSERT(index0 < mSize && index1 < mSize);
- if (index0 < mSize && index1 < mSize) {
- ElementType temp = std::move(mData[index0]);
- mData[index0] = std::move(mData[index1]);
- mData[index1] = std::move(temp);
+ if (index0 < mSize && index1 < mSize && index0 != index1) {
+ typename std::aligned_storage<sizeof(ElementType),
+ alignof(ElementType)>::type tempStorage;
+ ElementType& temp = *reinterpret_cast<ElementType *>(&tempStorage);
+ uninitializedMoveOrCopy(&mData[index0], 1, &temp);
+ moveOrCopyAssign(mData[index0], mData[index1]);
+ moveOrCopyAssign(mData[index1], temp);
}
}
diff --git a/util/include/chre/util/entry_points.h b/util/include/chre/util/entry_points.h
index cd794a7..e5350d5 100644
--- a/util/include/chre/util/entry_points.h
+++ b/util/include/chre/util/entry_points.h
@@ -17,19 +17,18 @@
#ifndef CHRE_UTIL_ENTRY_POINTS_H_
#define CHRE_UTIL_ENTRY_POINTS_H_
-namespace chre {
+#include <stdbool.h>
+#include <stdint.h>
-//! The type for the Nanoapp start function pointer.
-typedef bool (NanoappStartFunction)();
+//! @see nanoappStart()
+typedef bool (chreNanoappStartFunction)();
-//! The type of the Nanoapp handle event function pointer.
-typedef void (NanoappHandleEventFunction)(uint32_t senderInstanceId,
- uint16_t eventType,
- const void *eventData);
+//! @see nanoappHandleEvent()
+typedef void (chreNanoappHandleEventFunction)(uint32_t senderInstanceId,
+ uint16_t eventType,
+ const void *eventData);
-//! The type of the Nanoapp stop function pointer.
-typedef void (NanoappStopFunction)();
-
-} // namespace chre
+//! @see nanoappEnd()
+typedef void (chreNanoappEndFunction)();
#endif // CHRE_UTIL_ENTRY_POINTS_H_
diff --git a/util/include/chre/util/fixed_size_vector_impl.h b/util/include/chre/util/fixed_size_vector_impl.h
index 8e8fe55..90f131a 100644
--- a/util/include/chre/util/fixed_size_vector_impl.h
+++ b/util/include/chre/util/fixed_size_vector_impl.h
@@ -17,10 +17,10 @@
#ifndef CHRE_UTIL_FIXED_SIZE_VECTOR_IMPL_H_
#define CHRE_UTIL_FIXED_SIZE_VECTOR_IMPL_H_
-#include <utility>
+#include <new>
#include "chre/platform/assert.h"
-#include "chre/util/fixed_size_vector.h"
+#include "chre/util/memory.h"
namespace chre {
@@ -59,7 +59,7 @@
const ElementType& element) {
CHRE_ASSERT(!full());
if (!full()) {
- data()[mSize++] = element;
+ new (&data()[mSize++]) ElementType(element);
}
}
@@ -100,7 +100,7 @@
if (index < mSize) {
mSize--;
for (size_t i = index; i < mSize; i++) {
- data()[i] = std::move(data()[i + 1]);
+ moveOrCopyAssign(data()[i], data()[i + 1]);
}
data()[mSize].~ElementType();
@@ -111,10 +111,13 @@
void FixedSizeVector<ElementType, kCapacity>::swap(size_t index0,
size_t index1) {
CHRE_ASSERT(index0 < mSize && index1 < mSize);
- if (index0 < mSize && index1 < mSize) {
- ElementType temp = std::move(data()[index0]);
- data()[index0] = std::move(data()[index1]);
- data()[index1] = std::move(temp);
+ if (index0 < mSize && index1 < mSize && index0 != index1) {
+ typename std::aligned_storage<sizeof(ElementType),
+ alignof(ElementType)>::type tempStorage;
+ ElementType& temp = *reinterpret_cast<ElementType *>(&tempStorage);
+ uninitializedMoveOrCopy(&data()[index0], 1, &temp);
+ moveOrCopyAssign(data()[index0], data()[index1]);
+ moveOrCopyAssign(data()[index1], temp);
}
}
diff --git a/util/include/chre/util/memory.h b/util/include/chre/util/memory.h
new file mode 100644
index 0000000..ccfb5ce
--- /dev/null
+++ b/util/include/chre/util/memory.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2017 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 CHRE_UTIL_MEMORY_H_
+#define CHRE_UTIL_MEMORY_H_
+
+namespace chre {
+
+/**
+ * Destroys count objects starting at first. This function is similar to
+ * std::destroy_n.
+ *
+ * @param first Starting address of count objects to destroy
+ * @param count The number of objects to destroy
+ */
+template<typename ElementType>
+void destroy(ElementType *first, size_t count);
+
+/**
+ * Performs move assignment (dest = std::move(source)) if supported by
+ * ElementType, otherwise copy assignment (dest = source).
+ */
+template<typename ElementType>
+void moveOrCopyAssign(ElementType& dest, ElementType& source);
+
+/**
+ * Initializes a new block of memory by transferring objects from another block,
+ * using memcpy if valid for the underlying type, or the move constructor if
+ * available, or the copy constructor. This function is similar to
+ * std::uninitialized_move_n.
+ *
+ * @param source The beginning of the data to transfer
+ * @param count The number of elements to transfer
+ * @param dest An uninitialized buffer to be populated with count elements
+ */
+template<typename ElementType>
+void uninitializedMoveOrCopy(ElementType *source, size_t count,
+ ElementType *dest);
+
+} // namespace chre
+
+#include "chre/util/memory_impl.h"
+
+#endif // CHRE_UTIL_MEMORY_H
diff --git a/util/include/chre/util/memory_impl.h b/util/include/chre/util/memory_impl.h
new file mode 100644
index 0000000..cf9b712
--- /dev/null
+++ b/util/include/chre/util/memory_impl.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2017 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 CHRE_UTIL_MEMORY_IMPL_H_
+#define CHRE_UTIL_MEMORY_IMPL_H_
+
+#include <cstring>
+#include <new>
+#include <type_traits>
+#include <utility>
+
+namespace chre {
+
+template<typename ElementType>
+inline void destroy(ElementType *first, size_t count) {
+ for (size_t i = 0; i < count; i++) {
+ first[i].~ElementType();
+ }
+}
+
+//! Overload used when the type is move assignable
+template<typename ElementType>
+inline void moveOrCopyAssign(ElementType& dest, ElementType& source,
+ std::true_type) {
+ dest = std::move(source);
+}
+
+//! Overload used when the type is not move assignable
+template<typename ElementType>
+inline void moveOrCopyAssign(ElementType& dest, ElementType& source,
+ std::false_type) {
+ dest = source;
+}
+
+template<typename ElementType>
+inline void moveOrCopyAssign(ElementType& dest, ElementType& source) {
+ moveOrCopyAssign(dest, source,
+ typename std::is_move_assignable<ElementType>::type());
+}
+
+//! Overload used when type is trivially copy constructible
+template<typename ElementType>
+inline void uninitializedMoveOrCopy(ElementType *source, size_t count,
+ ElementType *dest, std::true_type) {
+ std::memcpy(dest, source, count * sizeof(ElementType));
+}
+
+//! Overload used when type is not trivially copy constructible, but is move
+//! constructible
+template<typename ElementType>
+inline void uninitializedMoveOrCopy(ElementType *source, size_t count,
+ ElementType *dest, std::false_type,
+ std::true_type) {
+ for (size_t i = 0; i < count; i++) {
+ new (&dest[i]) ElementType(std::move(source[i]));
+ }
+}
+
+//! Overload used when type is not trivially copy constructible or move
+//! constructible
+template<typename ElementType>
+inline void uninitializedMoveOrCopy(ElementType *source, size_t count,
+ ElementType *dest, std::false_type,
+ std::false_type) {
+ for (size_t i = 0; i < count; i++) {
+ new (&dest[i]) ElementType(source[i]);
+ }
+}
+
+//! Overload used when type is not trivially copy constructible
+template<typename ElementType>
+inline void uninitializedMoveOrCopy(
+ ElementType *source, size_t count, ElementType *dest, std::false_type) {
+ // Check the assumption that if is_move_constructible is false, then
+ // is_copy_constructible is true
+ static_assert(std::is_move_constructible<ElementType>()
+ || std::is_copy_constructible<ElementType>(),
+ "Object must be copy- or move- constructible to use "
+ "unintializedMoveOrCopy");
+ uninitializedMoveOrCopy(
+ source, count, dest, std::false_type(),
+ typename std::is_move_constructible<ElementType>::type());
+}
+
+template<typename ElementType>
+inline void uninitializedMoveOrCopy(ElementType *source, size_t count,
+ ElementType *dest) {
+ // TODO: we should be able to use std::is_trivially_copy_constructible here,
+ // but it's not found in the linux x86 build, because our build uses GCC 4.8's
+ // C++ standard library, which doesn't support it. Works in the SLPI build,
+ // though...
+ uninitializedMoveOrCopy(
+ source, count, dest, typename std::is_trivial<ElementType>::type());
+ //typename std::is_trivially_copy_constructible<ElementType>::type());
+}
+
+} // namespace chre
+
+#endif // CHRE_UTIL_MEMORY_IMPL_H_
diff --git a/util/include/chre/util/nanoapp/app_id.h b/util/include/chre/util/nanoapp/app_id.h
new file mode 100644
index 0000000..fca6257
--- /dev/null
+++ b/util/include/chre/util/nanoapp/app_id.h
@@ -0,0 +1,79 @@
+
+/*
+ * Copyright (C) 2017 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 CHRE_UTIL_NANOAPP_APP_ID_H_
+#define CHRE_UTIL_NANOAPP_APP_ID_H_
+
+#include <chre/common.h>
+#include <stdint.h>
+
+/**
+ * @file
+ * Helpers for defining static nanoapp IDs, e.g. for use with
+ * CHRE_STATIC_NANOAPP_INIT.
+ */
+
+//! Sample Vendor ID for example nanoapps. The vendor ID portion is the 5 most
+//! significant bytes of the app ID. This vendor ID should not appear in
+//! production.
+#define CHRE_VENDOR_ID_EXAMPLE UINT64_C(0x0123456789000000)
+
+namespace chre {
+
+/**
+ * Constructs a fully qualified nanoapp ID from a vendor portion (most
+ * significant 5 bytes) and app number (least significant 3 bytes)
+ *
+ * @param vendor Value with vendor unique identifier in the most significant 5
+ * bytes
+ * @param appNumber Value with vendor-scoped app number in the least significant
+ * 3 bytes
+ *
+ * @return app ID combining vendor and app number
+ */
+constexpr uint64_t makeNanoappId(uint64_t vendor, uint32_t appNumber) {
+ return ((vendor & CHRE_VENDOR_ID_MASK) | (appNumber & ~CHRE_VENDOR_ID_MASK));
+}
+
+/**
+ * @return App ID combining the given 3-byte app number and Google's 5-byte
+ * vendor ID
+ */
+constexpr uint64_t makeExampleNanoappId(uint32_t appNumber) {
+ return makeNanoappId(CHRE_VENDOR_ID_EXAMPLE, appNumber);
+}
+
+/**
+ * @return App ID combining the given 3-byte app number and Google's 5-byte
+ * vendor ID
+ */
+constexpr uint64_t makeGoogleNanoappId(uint32_t appNumber) {
+ return makeNanoappId(CHRE_VENDOR_ID_GOOGLE, appNumber);
+}
+
+constexpr uint64_t kHelloWorldAppId = makeExampleNanoappId(1);
+constexpr uint64_t kMessageWorldAppId = makeExampleNanoappId(2);
+constexpr uint64_t kTimerWorldAppId = makeExampleNanoappId(3);
+constexpr uint64_t kSensorWorldAppId = makeExampleNanoappId(4);
+constexpr uint64_t kGnssWorldAppId = makeExampleNanoappId(5);
+constexpr uint64_t kWifiWorldAppId = makeExampleNanoappId(6);
+constexpr uint64_t kWwanWorldAppId = makeExampleNanoappId(7);
+constexpr uint64_t kImuCalAppId = makeExampleNanoappId(8);
+
+} // namespace chre
+
+#endif // CHRE_UTIL_NANOAPP_APP_ID_H_
diff --git a/util/include/chre/util/unique_ptr.h b/util/include/chre/util/unique_ptr.h
index 2fbeff1..78feb53 100644
--- a/util/include/chre/util/unique_ptr.h
+++ b/util/include/chre/util/unique_ptr.h
@@ -23,20 +23,33 @@
/**
* Wraps a pointer to a dynamically allocated object and manages the underlying
- * memory. The goal is to be similar to std::unique_ptr.
+ * memory. The goal is to be similar to std::unique_ptr, but we do not support
+ * custom deleters - deletion is always done via memoryFree().
*/
template<typename ObjectType>
class UniquePtr : public NonCopyable {
public:
/**
- * Allocates and constructs a new object of type ObjectType on the heap. If
- * memory allocation fails the constructor is not invoked. This constructor is
- * similar to std::make_unique.
- *
- * @param args The arguments to pass to the object's constructor.
+ * Construct a UniquePtr instance that does not own any object.
*/
- template<typename... Args>
- UniquePtr(Args&&... args);
+ UniquePtr();
+
+ /**
+ * Constructs a UniquePtr instance that owns the given object, and will free
+ * its memory when the UniquePtr is destructed.
+ *
+ * @param object Pointer to an object allocated via memoryAlloc. It is not
+ * valid for this object's memory to come from any other source,
+ * including the stack, or static allocation on the heap.
+ */
+ UniquePtr(ObjectType *object);
+
+ /**
+ * Constructs a new UniquePtr via moving the Object from another UniquePtr.
+ *
+ * @param other UniquePtr instance to move into this object
+ */
+ UniquePtr(UniquePtr<ObjectType>&& other);
/**
* Deconstructs the object (if necessary) and releases associated memory.
@@ -44,9 +57,9 @@
~UniquePtr();
/**
- * Determines if the object was constructed correctly.
+ * Determines if this UniquePtr owns an object, or references null.
*
- * @return true if the object is null and not constructed.
+ * @return true if get() returns nullptr
*/
bool isNull() const;
@@ -59,7 +72,7 @@
/**
* Releases ownership of the underlying object, so it will not be freed when
* this object is destructed. After this function returns, get() will return
- * null.
+ * nullptr.
*
* @return A pointer to the underlying object (i.e. what get() would return
* prior to this function call)
@@ -96,6 +109,16 @@
ObjectType *mObject;
};
+/**
+ * Allocates and constructs a new object of type ObjectType on the heap, and
+ * returns a UniquePtr that owns the object. This function is similar to
+ * std::make_unique.
+ *
+ * @param args The arguments to pass to the object's constructor.
+ */
+template<typename ObjectType, typename... Args>
+UniquePtr<ObjectType> MakeUnique(Args&&... args);
+
} // namespace chre
#include "chre/util/unique_ptr_impl.h"
diff --git a/util/include/chre/util/unique_ptr_impl.h b/util/include/chre/util/unique_ptr_impl.h
index 3059abc..aac1411 100644
--- a/util/include/chre/util/unique_ptr_impl.h
+++ b/util/include/chre/util/unique_ptr_impl.h
@@ -24,12 +24,15 @@
namespace chre {
template<typename ObjectType>
-template<typename... Args>
-UniquePtr<ObjectType>::UniquePtr(Args&&... args) {
- mObject = static_cast<ObjectType *>(memoryAlloc(sizeof(ObjectType)));
- if (mObject != nullptr) {
- new (mObject) ObjectType(std::forward<Args>(args)...);
- }
+UniquePtr<ObjectType>::UniquePtr() : mObject(nullptr) {}
+
+template<typename ObjectType>
+UniquePtr<ObjectType>::UniquePtr(ObjectType *object) : mObject(object) {}
+
+template<typename ObjectType>
+UniquePtr<ObjectType>::UniquePtr(UniquePtr<ObjectType>&& other) {
+ mObject = other.mObject;
+ other.mObject = nullptr;
}
template<typename ObjectType>
@@ -82,6 +85,12 @@
return *this;
}
+template<typename ObjectType, typename... Args>
+inline UniquePtr<ObjectType> MakeUnique(Args&&... args) {
+ return UniquePtr<ObjectType>(memoryAlloc<ObjectType>(
+ std::forward<Args>(args)...));
+}
+
} // namespace chre
#endif // CHRE_UTIL_UNIQUE_PTR_IMPL_H_
diff --git a/util/tests/dynamic_vector_test.cc b/util/tests/dynamic_vector_test.cc
index 5b167e9..a660036 100644
--- a/util/tests/dynamic_vector_test.cc
+++ b/util/tests/dynamic_vector_test.cc
@@ -19,6 +19,8 @@
#include "chre/util/dynamic_vector.h"
#include "chre/util/macros.h"
+#include <stdint.h>
+
using chre::DynamicVector;
namespace {
@@ -52,39 +54,61 @@
TEST(DynamicVector, EmptyByDefault) {
DynamicVector<int> vector;
- ASSERT_EQ(vector.data(), nullptr);
- ASSERT_EQ(vector.size(), 0);
- ASSERT_EQ(vector.capacity(), 0);
+ EXPECT_EQ(vector.data(), nullptr);
+ EXPECT_TRUE(vector.empty());
+ EXPECT_EQ(vector.size(), 0);
+ EXPECT_EQ(vector.capacity(), 0);
+ vector.clear();
}
TEST(DynamicVector, PushBackAndRead) {
DynamicVector<int> vector;
ASSERT_TRUE(vector.push_back(0x1337));
- ASSERT_EQ(vector[0], 0x1337);
- ASSERT_EQ(vector.data()[0], 0x1337);
+ EXPECT_EQ(vector.size(), 1);
+ EXPECT_EQ(vector.capacity(), 1);
+ EXPECT_EQ(vector.data(), &vector[0]);
+ EXPECT_FALSE(vector.empty());
+ EXPECT_EQ(vector[0], 0x1337);
}
-TEST(DynamicVector, PushBackReserveAndRead) {
+TEST(DynamicVector, PushBackReserveAndReadTrivialType) {
DynamicVector<int> vector;
- ASSERT_TRUE(vector.push_back(0x1337));
+ ASSERT_TRUE(vector.emplace_back(0x1337));
ASSERT_TRUE(vector.push_back(0xface));
- ASSERT_TRUE(vector.reserve(4));
- ASSERT_EQ(vector[0], 0x1337);
- ASSERT_EQ(vector.data()[0], 0x1337);
- ASSERT_EQ(vector[1], 0xface);
- ASSERT_EQ(vector.data()[1], 0xface);
+ int x = 0xcafe;
+ ASSERT_TRUE(vector.push_back(std::move(x)));
+ ASSERT_TRUE(vector.insert(vector.size(), 0xd00d));
+ EXPECT_EQ(vector.size(), 4);
+ EXPECT_EQ(vector.capacity(), 4);
+ EXPECT_EQ(vector[0], 0x1337);
+ EXPECT_EQ(vector[1], 0xface);
+ EXPECT_EQ(vector[2], 0xcafe);
+ EXPECT_EQ(vector[3], 0xd00d);
+
+ ASSERT_TRUE(vector.reserve(8));
+ EXPECT_EQ(vector.size(), 4);
+ EXPECT_EQ(vector.capacity(), 8);
+ EXPECT_EQ(vector[0], 0x1337);
+ EXPECT_EQ(vector[1], 0xface);
+ EXPECT_EQ(vector[2], 0xcafe);
+ EXPECT_EQ(vector[3], 0xd00d);
}
+constexpr int kConstructedMagic = 0xdeadbeef;
+
class MovableButNonCopyable : public chre::NonCopyable {
public:
MovableButNonCopyable(int value) : mValue(value) {}
MovableButNonCopyable(MovableButNonCopyable&& other) {
mValue = other.mValue;
+ other.mValue = -1;
}
MovableButNonCopyable& operator=(MovableButNonCopyable&& other) {
+ assert(mMagic == kConstructedMagic);
mValue = other.mValue;
+ other.mValue = -1;
return *this;
}
@@ -93,6 +117,7 @@
}
private:
+ int mMagic = kConstructedMagic;
int mValue;
};
@@ -100,11 +125,20 @@
DynamicVector<MovableButNonCopyable> vector;
ASSERT_TRUE(vector.emplace_back(0x1337));
ASSERT_TRUE(vector.emplace_back(0xface));
- ASSERT_TRUE(vector.reserve(4));
+ MovableButNonCopyable mbnc(0xcafe);
+ ASSERT_TRUE(vector.push_back(std::move(mbnc)));
+ EXPECT_EQ(mbnc.getValue(), -1);
+ MovableButNonCopyable mbnc2(0xd00d);
+ ASSERT_TRUE(vector.insert(vector.size(), std::move(mbnc2)));
+ EXPECT_EQ(mbnc2.getValue(), -1);
+
+ ASSERT_TRUE(vector.reserve(8));
EXPECT_EQ(vector[0].getValue(), 0x1337);
- EXPECT_EQ(vector.data()[0].getValue(), 0x1337);
EXPECT_EQ(vector[1].getValue(), 0xface);
- EXPECT_EQ(vector.data()[1].getValue(), 0xface);
+ EXPECT_EQ(vector[2].getValue(), 0xcafe);
+ EXPECT_EQ(vector[3].getValue(), 0xd00d);
+ EXPECT_EQ(vector.size(), 4);
+ EXPECT_EQ(vector.capacity(), 8);
}
class CopyableButNonMovable {
@@ -115,13 +149,13 @@
mValue = other.mValue;
}
- CopyableButNonMovable(CopyableButNonMovable&& other) = delete;
-
CopyableButNonMovable& operator=(const CopyableButNonMovable& other) {
+ assert(mMagic == kConstructedMagic);
mValue = other.mValue;
return *this;
}
+ CopyableButNonMovable(CopyableButNonMovable&& other) = delete;
CopyableButNonMovable& operator=(CopyableButNonMovable&& other) = delete;
int getValue() const {
@@ -129,18 +163,26 @@
}
private:
+ int mMagic = kConstructedMagic;
int mValue;
};
TEST(DynamicVector, PushBackReserveAndReadCopyableButNonMovable) {
DynamicVector<CopyableButNonMovable> vector;
- ASSERT_TRUE(vector.emplace_back(0xcafe));
+ ASSERT_TRUE(vector.emplace_back(0x1337));
ASSERT_TRUE(vector.emplace_back(0xface));
- ASSERT_TRUE(vector.reserve(4));
- EXPECT_EQ(vector[0].getValue(), 0xcafe);
- EXPECT_EQ(vector.data()[0].getValue(), 0xcafe);
+ CopyableButNonMovable cbnm(0xcafe);
+ ASSERT_TRUE(vector.push_back(cbnm));
+ CopyableButNonMovable cbnm2(0xd00d);
+ ASSERT_TRUE(vector.insert(vector.size(), cbnm2));
+
+ ASSERT_TRUE(vector.reserve(8));
+ EXPECT_EQ(vector[0].getValue(), 0x1337);
EXPECT_EQ(vector[1].getValue(), 0xface);
- EXPECT_EQ(vector.data()[1].getValue(), 0xface);
+ EXPECT_EQ(vector[2].getValue(), 0xcafe);
+ EXPECT_EQ(vector[3].getValue(), 0xd00d);
+ EXPECT_EQ(vector.size(), 4);
+ EXPECT_EQ(vector.capacity(), 8);
}
class MovableAndCopyable {
@@ -152,18 +194,21 @@
}
MovableAndCopyable(MovableAndCopyable&& other) {
- mValue = other.mValue;
+ // The move constructor multiplies the value by 2 so that we can see that it
+ // was used
+ mValue = other.mValue * 2;
}
MovableAndCopyable& operator=(const MovableAndCopyable& other) {
+ assert(mMagic == kConstructedMagic);
mValue = other.mValue;
return *this;
}
MovableAndCopyable& operator=(MovableAndCopyable&& other) {
- // The move operation multiplies the value by 2 so that we can see that the
- // move assignment operator was used.
+ assert(mMagic == kConstructedMagic);
mValue = other.mValue * 2;
+ other.mValue = -1;
return *this;
}
@@ -172,11 +217,12 @@
}
private:
+ int mMagic = kConstructedMagic;
int mValue;
};
-TEST(DynamicVector, PushBackReserveAndReadMovableAndCopyable) {
- // Ensure that preference is given to std::move.
+TEST(DynamicVector, ReservePrefersMove) {
+ // Ensure that preference is given to std::move in reserve()
DynamicVector<MovableAndCopyable> vector;
// Reserve enough space for the first two elements.
@@ -190,9 +236,7 @@
// Move on this type results in a multiplication by 2. Verify that all
// elements have been multiplied by 2.
EXPECT_EQ(vector[0].getValue(), 2000);
- EXPECT_EQ(vector.data()[0].getValue(), 2000);
EXPECT_EQ(vector[1].getValue(), 4000);
- EXPECT_EQ(vector.data()[1].getValue(), 4000);
}
/**
@@ -208,6 +252,13 @@
sConstructedCounter++;
}
+ Foo(const Foo& other) {
+ value = other.value;
+ sConstructedCounter++;
+ }
+
+ Foo(Foo&& other) = delete;
+
/**
* Tear down the object, decrementing the number of objects that have been
* constructed of this type.
@@ -217,7 +268,7 @@
}
//! The number of objects of this type that have been constructed.
- static size_t sConstructedCounter;
+ static ssize_t sConstructedCounter;
//! The value stored in the object to verify the contents of this object after
//! construction.
@@ -225,9 +276,10 @@
};
//! Storage for the Foo reference counter.
-size_t Foo::sConstructedCounter = 0;
+ssize_t Foo::sConstructedCounter = 0;
TEST(DynamicVector, EmplaceBackAndDestruct) {
+ Foo::sConstructedCounter = 0;
{
DynamicVector<Foo> vector;
ASSERT_TRUE(vector.emplace_back(1000));
@@ -236,26 +288,75 @@
ASSERT_TRUE(vector.emplace_back(4000));
ASSERT_EQ(vector[0].value, 1000);
- ASSERT_EQ(vector.data()[0].value, 1000);
ASSERT_EQ(vector[1].value, 2000);
- ASSERT_EQ(vector.data()[1].value, 2000);
ASSERT_EQ(vector[2].value, 3000);
- ASSERT_EQ(vector.data()[2].value, 3000);
ASSERT_EQ(vector[3].value, 4000);
- ASSERT_EQ(vector.data()[3].value, 4000);
- ASSERT_EQ(Foo::sConstructedCounter, 4);
+ EXPECT_EQ(Foo::sConstructedCounter, 4);
}
- ASSERT_EQ(Foo::sConstructedCounter, 0);
+ EXPECT_EQ(Foo::sConstructedCounter, 0);
}
TEST(DynamicVector, InsertEmpty) {
DynamicVector<int> vector;
EXPECT_CHRE_ASSERT(EXPECT_FALSE(vector.insert(1, 0x1337)));
+
+ // Insert to empty vector
ASSERT_TRUE(vector.insert(0, 0x1337));
EXPECT_EQ(vector[0], 0x1337);
- EXPECT_EQ(vector.data()[0], 0x1337);
+
+ // Insert at end triggering grow
+ ASSERT_EQ(vector.capacity(), 1);
+ EXPECT_TRUE(vector.insert(1, 0xface));
+ EXPECT_EQ(vector[0], 0x1337);
+ EXPECT_EQ(vector[1], 0xface);
+
+ // Insert at beginning triggering grow
+ ASSERT_EQ(vector.capacity(), 2);
+ EXPECT_TRUE(vector.insert(0, 0xcafe));
+ EXPECT_EQ(vector[0], 0xcafe);
+ EXPECT_EQ(vector[1], 0x1337);
+ EXPECT_EQ(vector[2], 0xface);
+
+ // Insert at middle with spare capacity
+ ASSERT_EQ(vector.capacity(), 4);
+ EXPECT_TRUE(vector.insert(1, 0xdead));
+ EXPECT_EQ(vector[0], 0xcafe);
+ EXPECT_EQ(vector[1], 0xdead);
+ EXPECT_EQ(vector[2], 0x1337);
+ EXPECT_EQ(vector[3], 0xface);
+
+ // Insert at middle triggering grow
+ ASSERT_EQ(vector.capacity(), 4);
+ EXPECT_TRUE(vector.insert(2, 0xbeef));
+ EXPECT_EQ(vector[0], 0xcafe);
+ EXPECT_EQ(vector[1], 0xdead);
+ EXPECT_EQ(vector[2], 0xbeef);
+ EXPECT_EQ(vector[3], 0x1337);
+ EXPECT_EQ(vector[4], 0xface);
+
+ // Insert at beginning with spare capacity
+ ASSERT_EQ(vector.capacity(), 8);
+ ASSERT_EQ(vector.size(), 5);
+ EXPECT_TRUE(vector.insert(0, 0xabad));
+ EXPECT_EQ(vector[0], 0xabad);
+ EXPECT_EQ(vector[1], 0xcafe);
+ EXPECT_EQ(vector[2], 0xdead);
+ EXPECT_EQ(vector[3], 0xbeef);
+ EXPECT_EQ(vector[4], 0x1337);
+ EXPECT_EQ(vector[5], 0xface);
+
+ // Insert at end with spare capacity
+ ASSERT_EQ(vector.size(), 6);
+ EXPECT_TRUE(vector.insert(vector.size(), 0xc0de));
+ EXPECT_EQ(vector[0], 0xabad);
+ EXPECT_EQ(vector[1], 0xcafe);
+ EXPECT_EQ(vector[2], 0xdead);
+ EXPECT_EQ(vector[3], 0xbeef);
+ EXPECT_EQ(vector[4], 0x1337);
+ EXPECT_EQ(vector[5], 0xface);
+ EXPECT_EQ(vector[6], 0xc0de);
}
TEST(DynamicVector, PushBackInsertInMiddleAndRead) {
@@ -266,13 +367,9 @@
ASSERT_TRUE(vector.insert(1, 0xbeef));
ASSERT_EQ(vector[0], 0x1337);
- ASSERT_EQ(vector.data()[0], 0x1337);
ASSERT_EQ(vector[1], 0xbeef);
- ASSERT_EQ(vector.data()[1], 0xbeef);
ASSERT_EQ(vector[2], 0xface);
- ASSERT_EQ(vector.data()[2], 0xface);
ASSERT_EQ(vector[3], 0xcafe);
- ASSERT_EQ(vector.data()[3], 0xcafe);
}
TEST(DynamicVector, PushBackAndErase) {
@@ -285,11 +382,8 @@
vector.erase(1);
ASSERT_EQ(vector[0], 0x1337);
- ASSERT_EQ(vector.data()[0], 0x1337);
ASSERT_EQ(vector[1], 0xbeef);
- ASSERT_EQ(vector.data()[1], 0xbeef);
ASSERT_EQ(vector[2], 0xface);
- ASSERT_EQ(vector.data()[2], 0xface);
ASSERT_EQ(vector.size(), 3);
}
@@ -314,8 +408,9 @@
resetDestructorCounts();
DynamicVector<Dummy> vector;
+ vector.reserve(4);
for (size_t i = 0; i < 4; ++i) {
- vector.push_back(Dummy());
+ vector.emplace_back();
vector[i].setValue(i);
}
@@ -345,8 +440,9 @@
resetDestructorCounts();
DynamicVector<Dummy> vector;
+ vector.reserve(4);
for (size_t i = 0; i < 4; ++i) {
- vector.push_back(Dummy());
+ vector.emplace_back();
vector[i].setValue(i);
}
@@ -774,3 +870,8 @@
EXPECT_EQ(vector.size(), 1);
EXPECT_EQ(vector.capacity(), 2);
}
+
+TEST(DynamicVector, RidiculouslyHugeReserveFails) {
+ DynamicVector<int> vector;
+ ASSERT_FALSE(vector.reserve(SIZE_MAX));
+}
diff --git a/util/tests/unique_ptr_test.cc b/util/tests/unique_ptr_test.cc
index 0f1dc6d..5d53901 100644
--- a/util/tests/unique_ptr_test.cc
+++ b/util/tests/unique_ptr_test.cc
@@ -3,6 +3,7 @@
#include "chre/util/unique_ptr.h"
using chre::UniquePtr;
+using chre::MakeUnique;
struct Value {
Value(int value) : value(value) {
@@ -25,7 +26,7 @@
int Value::constructionCounter = 0;
TEST(UniquePtr, Construct) {
- UniquePtr<Value> myInt(0xcafe);
+ UniquePtr<Value> myInt = MakeUnique<Value>(0xcafe);
ASSERT_FALSE(myInt.isNull());
EXPECT_EQ(myInt.get()->value, 0xcafe);
EXPECT_EQ(myInt->value, 0xcafe);
@@ -33,15 +34,25 @@
EXPECT_EQ(myInt[0].value, 0xcafe);
}
+TEST(UniquePtr, MoveConstruct) {
+ UniquePtr<Value> myInt = MakeUnique<Value>(0xcafe);
+ ASSERT_FALSE(myInt.isNull());
+ Value *value = myInt.get();
+
+ UniquePtr<Value> moved(std::move(myInt));
+ EXPECT_EQ(moved.get(), value);
+ EXPECT_EQ(myInt.get(), nullptr);
+}
+
TEST(UniquePtr, Move) {
Value::constructionCounter = 0;
{
- UniquePtr<Value> myInt(0xcafe);
+ UniquePtr<Value> myInt = MakeUnique<Value>(0xcafe);
ASSERT_FALSE(myInt.isNull());
EXPECT_EQ(Value::constructionCounter, 1);
- UniquePtr<Value> myMovedInt(0);
+ UniquePtr<Value> myMovedInt = MakeUnique<Value>(0);
ASSERT_FALSE(myMovedInt.isNull());
EXPECT_EQ(Value::constructionCounter, 2);
myMovedInt = std::move(myInt);
@@ -58,7 +69,7 @@
Value *value1, *value2;
{
- UniquePtr<Value> myInt(0xcafe);
+ UniquePtr<Value> myInt = MakeUnique<Value>(0xcafe);
ASSERT_FALSE(myInt.isNull());
EXPECT_EQ(Value::constructionCounter, 1);
value1 = myInt.get();