Merge "Correct type of appData field" into pi-dev
diff --git a/camera/device/3.2/default/CameraDeviceSession.cpp b/camera/device/3.2/default/CameraDeviceSession.cpp
index 5f89cde..60a57cd 100644
--- a/camera/device/3.2/default/CameraDeviceSession.cpp
+++ b/camera/device/3.2/default/CameraDeviceSession.cpp
@@ -645,7 +645,10 @@
result.fmqResultSize = result.result.size();
result.result.resize(0);
} else {
- ALOGW("%s: couldn't utilize fmq, fall back to hwbinder", __FUNCTION__);
+ ALOGW("%s: couldn't utilize fmq, fall back to hwbinder, result size: %zu,"
+ "shared message queue available size: %zu",
+ __FUNCTION__, result.result.size(),
+ mResultMetadataQueue->availableToWrite());
result.fmqResultSize = 0;
}
}
diff --git a/camera/device/3.4/default/ExternalCameraDevice.cpp b/camera/device/3.4/default/ExternalCameraDevice.cpp
index 6b05d4a..ee7ffaa 100644
--- a/camera/device/3.4/default/ExternalCameraDevice.cpp
+++ b/camera/device/3.4/default/ExternalCameraDevice.cpp
@@ -42,6 +42,9 @@
V4L2_PIX_FMT_MJPEG
}}; // double braces required in C++11
+constexpr int MAX_RETRY = 5; // Allow retry v4l2 open failures a few times.
+constexpr int OPEN_RETRY_SLEEP_US = 100000; // 100ms * MAX_RETRY = 0.5 seconds
+
} // anonymous namespace
ExternalCameraDevice::ExternalCameraDevice(
@@ -122,11 +125,22 @@
unique_fd fd(::open(mCameraId.c_str(), O_RDWR));
if (fd.get() < 0) {
- ALOGE("%s: v4l2 device open %s failed: %s",
- __FUNCTION__, mCameraId.c_str(), strerror(errno));
- mLock.unlock();
- _hidl_cb(Status::INTERNAL_ERROR, nullptr);
- return Void();
+ int numAttempt = 0;
+ do {
+ ALOGW("%s: v4l2 device %s open failed, wait 33ms and try again",
+ __FUNCTION__, mCameraId.c_str());
+ usleep(OPEN_RETRY_SLEEP_US); // sleep and try again
+ fd.reset(::open(mCameraId.c_str(), O_RDWR));
+ numAttempt++;
+ } while (fd.get() < 0 && numAttempt <= MAX_RETRY);
+
+ if (fd.get() < 0) {
+ ALOGE("%s: v4l2 device open %s failed: %s",
+ __FUNCTION__, mCameraId.c_str(), strerror(errno));
+ mLock.unlock();
+ _hidl_cb(Status::INTERNAL_ERROR, nullptr);
+ return Void();
+ }
}
session = new ExternalCameraDeviceSession(
diff --git a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
index bb11d7c..1af3f39 100644
--- a/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
+++ b/camera/device/3.4/default/ExternalCameraDeviceSession.cpp
@@ -49,7 +49,7 @@
// method
constexpr int MAX_RETRY = 15; // Allow retry some ioctl failures a few times to account for some
// webcam showing temporarily ioctl failures.
-constexpr int IOCTL_RETRY_SLEEP_US = 33000; // 33ms * MAX_RETRY = 5 seconds
+constexpr int IOCTL_RETRY_SLEEP_US = 33000; // 33ms * MAX_RETRY = 0.5 seconds
// Constants for tryLock during dumpstate
static constexpr int kDumpLockRetries = 50;
@@ -115,6 +115,35 @@
return true;
}
+ struct v4l2_capability capability;
+ int ret = ioctl(mV4l2Fd.get(), VIDIOC_QUERYCAP, &capability);
+ std::string make, model;
+ if (ret < 0) {
+ ALOGW("%s v4l2 QUERYCAP failed", __FUNCTION__);
+ make = "Generic UVC webcam";
+ model = "Generic UVC webcam";
+ } else {
+ // capability.card is UTF-8 encoded
+ char card[32];
+ int j = 0;
+ for (int i = 0; i < 32; i++) {
+ if (capability.card[i] < 128) {
+ card[j++] = capability.card[i];
+ }
+ if (capability.card[i] == '\0') {
+ break;
+ }
+ }
+ if (j == 0 || card[j - 1] != '\0') {
+ make = "Generic UVC webcam";
+ model = "Generic UVC webcam";
+ } else {
+ make = card;
+ model = card;
+ }
+ }
+ mOutputThread->setExifMakeModel(make, model);
+
status_t status = initDefaultRequests();
if (status != OK) {
ALOGE("%s: init default requests failed!", __FUNCTION__);
@@ -826,6 +855,12 @@
ExternalCameraDeviceSession::OutputThread::~OutputThread() {}
+void ExternalCameraDeviceSession::OutputThread::setExifMakeModel(
+ const std::string& make, const std::string& model) {
+ mExifMake = make;
+ mExifModel = model;
+}
+
uint32_t ExternalCameraDeviceSession::OutputThread::getFourCcFromLayout(
const YCbCrLayout& layout) {
intptr_t cb = reinterpret_cast<intptr_t>(layout.cb);
@@ -1611,6 +1646,8 @@
utils->initialize();
utils->setFromMetadata(meta, jpegSize.width, jpegSize.height);
+ utils->setMake(mExifMake);
+ utils->setModel(mExifModel);
ret = utils->generateApp1(outputThumbnail ? &thumbCode[0] : 0, thumbCodeSize);
@@ -2150,7 +2187,7 @@
int numAttempt = 0;
while (ret < 0) {
ALOGW("%s: VIDIOC_S_FMT failed, wait 33ms and try again", __FUNCTION__);
- usleep(IOCTL_RETRY_SLEEP_US); // sleep 100 ms and try again
+ usleep(IOCTL_RETRY_SLEEP_US); // sleep and try again
ret = TEMP_FAILURE_RETRY(ioctl(mV4l2Fd.get(), VIDIOC_S_FMT, &fmt));
if (numAttempt == MAX_RETRY) {
break;
diff --git a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
index 14e5c9a..0b94c11 100644
--- a/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
+++ b/camera/device/3.4/default/include/ext_device_v3_4_impl/ExternalCameraDeviceSession.h
@@ -231,6 +231,7 @@
void dump(int fd);
virtual bool threadLoop() override;
+ void setExifMakeModel(const std::string& make, const std::string& model);
private:
static const uint32_t FLEX_YUV_GENERIC = static_cast<uint32_t>('F') |
static_cast<uint32_t>('L') << 8 | static_cast<uint32_t>('E') << 16 |
@@ -288,6 +289,9 @@
std::unordered_map<Size, sp<AllocatedFrame>, SizeHasher> mScaledYu12Frames;
YCbCrLayout mYu12FrameLayout;
YCbCrLayout mYu12ThumbFrameLayout;
+
+ std::string mExifMake;
+ std::string mExifModel;
};
// Protect (most of) HIDL interface methods from synchronized-entering
diff --git a/camera/provider/2.4/default/ExternalCameraProvider.cpp b/camera/provider/2.4/default/ExternalCameraProvider.cpp
index 285e96b..a4046d0 100644
--- a/camera/provider/2.4/default/ExternalCameraProvider.cpp
+++ b/camera/provider/2.4/default/ExternalCameraProvider.cpp
@@ -164,29 +164,35 @@
}
void ExternalCameraProvider::deviceAdded(const char* devName) {
- int fd = -1;
- if ((fd = ::open(devName, O_RDWR)) < 0) {
- ALOGE("%s open v4l2 device %s failed:%s", __FUNCTION__, devName, strerror(errno));
- return;
- }
+ {
+ base::unique_fd fd(::open(devName, O_RDWR));
+ if (fd.get() < 0) {
+ ALOGE("%s open v4l2 device %s failed:%s", __FUNCTION__, devName, strerror(errno));
+ return;
+ }
- do {
struct v4l2_capability capability;
- int ret = ioctl(fd, VIDIOC_QUERYCAP, &capability);
+ int ret = ioctl(fd.get(), VIDIOC_QUERYCAP, &capability);
if (ret < 0) {
ALOGE("%s v4l2 QUERYCAP %s failed", __FUNCTION__, devName);
- break;
+ return;
}
if (!(capability.device_caps & V4L2_CAP_VIDEO_CAPTURE)) {
ALOGW("%s device %s does not support VIDEO_CAPTURE", __FUNCTION__, devName);
- break;
+ return;
}
+ }
+ // See if we can initialize ExternalCameraDevice correctly
+ sp<device::V3_4::implementation::ExternalCameraDevice> deviceImpl =
+ new device::V3_4::implementation::ExternalCameraDevice(devName, mCfg);
+ if (deviceImpl == nullptr || deviceImpl->isInitFailed()) {
+ ALOGW("%s: Attempt to init camera device %s failed!", __FUNCTION__, devName);
+ return;
+ }
+ deviceImpl.clear();
- addExternalCamera(devName);
- } while (0);
-
- close(fd);
+ addExternalCamera(devName);
return;
}
diff --git a/cas/1.0/default/CasImpl.cpp b/cas/1.0/default/CasImpl.cpp
index 2ac1c4f..178020e 100644
--- a/cas/1.0/default/CasImpl.cpp
+++ b/cas/1.0/default/CasImpl.cpp
@@ -31,19 +31,8 @@
namespace V1_0 {
namespace implementation {
-struct CasImpl::PluginHolder : public RefBase {
-public:
- explicit PluginHolder(CasPlugin *plugin) : mPlugin(plugin) {}
- ~PluginHolder() { if (mPlugin != NULL) delete mPlugin; }
- CasPlugin* get() { return mPlugin; }
-
-private:
- CasPlugin *mPlugin;
- DISALLOW_EVIL_CONSTRUCTORS(PluginHolder);
-};
-
CasImpl::CasImpl(const sp<ICasListener> &listener)
- : mPluginHolder(NULL), mListener(listener) {
+ : mListener(listener) {
ALOGV("CTOR");
}
@@ -69,7 +58,8 @@
void CasImpl::init(const sp<SharedLibrary>& library, CasPlugin *plugin) {
mLibrary = library;
- mPluginHolder = new PluginHolder(plugin);
+ std::shared_ptr<CasPlugin> holder(plugin);
+ std::atomic_store(&mPluginHolder, holder);
}
void CasImpl::onEvent(
@@ -88,22 +78,22 @@
Return<Status> CasImpl::setPrivateData(const HidlCasData& pvtData) {
ALOGV("%s", __FUNCTION__);
- sp<PluginHolder> holder = mPluginHolder;
- if (holder == NULL) {
+ std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
return toStatus(INVALID_OPERATION);
}
- return toStatus(holder->get()->setPrivateData(pvtData));
+ return toStatus(holder->setPrivateData(pvtData));
}
Return<void> CasImpl::openSession(openSession_cb _hidl_cb) {
ALOGV("%s", __FUNCTION__);
CasSessionId sessionId;
- sp<PluginHolder> holder = mPluginHolder;
+ std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
status_t err = INVALID_OPERATION;
- if (holder != NULL) {
- err = holder->get()->openSession(&sessionId);
- holder.clear();
+ if (holder.get() != nullptr) {
+ err = holder->openSession(&sessionId);
+ holder.reset();
}
_hidl_cb(toStatus(err), sessionId);
@@ -115,87 +105,87 @@
const HidlCasSessionId &sessionId, const HidlCasData& pvtData) {
ALOGV("%s: sessionId=%s", __FUNCTION__,
sessionIdToString(sessionId).string());
- sp<PluginHolder> holder = mPluginHolder;
- if (holder == NULL) {
+ std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
return toStatus(INVALID_OPERATION);
}
- return toStatus(
- holder->get()->setSessionPrivateData(
- sessionId, pvtData));
+ return toStatus(holder->setSessionPrivateData(sessionId, pvtData));
}
Return<Status> CasImpl::closeSession(const HidlCasSessionId &sessionId) {
ALOGV("%s: sessionId=%s", __FUNCTION__,
sessionIdToString(sessionId).string());
- sp<PluginHolder> holder = mPluginHolder;
- if (holder == NULL) {
+ std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
return toStatus(INVALID_OPERATION);
}
- return toStatus(holder->get()->closeSession(sessionId));
+ return toStatus(holder->closeSession(sessionId));
}
Return<Status> CasImpl::processEcm(
const HidlCasSessionId &sessionId, const HidlCasData& ecm) {
ALOGV("%s: sessionId=%s", __FUNCTION__,
sessionIdToString(sessionId).string());
- sp<PluginHolder> holder = mPluginHolder;
- if (holder == NULL) {
+ std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
return toStatus(INVALID_OPERATION);
}
- return toStatus(holder->get()->processEcm(sessionId, ecm));
+ return toStatus(holder->processEcm(sessionId, ecm));
}
Return<Status> CasImpl::processEmm(const HidlCasData& emm) {
ALOGV("%s", __FUNCTION__);
- sp<PluginHolder> holder = mPluginHolder;
- if (holder == NULL) {
+ std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
return toStatus(INVALID_OPERATION);
}
- return toStatus(holder->get()->processEmm(emm));
+ return toStatus(holder->processEmm(emm));
}
Return<Status> CasImpl::sendEvent(
int32_t event, int32_t arg,
const HidlCasData& eventData) {
ALOGV("%s", __FUNCTION__);
- sp<PluginHolder> holder = mPluginHolder;
- if (holder == NULL) {
+ std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
return toStatus(INVALID_OPERATION);
}
- status_t err = holder->get()->sendEvent(event, arg, eventData);
+ status_t err = holder->sendEvent(event, arg, eventData);
return toStatus(err);
}
Return<Status> CasImpl::provision(const hidl_string& provisionString) {
ALOGV("%s: provisionString=%s", __FUNCTION__, provisionString.c_str());
- sp<PluginHolder> holder = mPluginHolder;
- if (holder == NULL) {
+ std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
return toStatus(INVALID_OPERATION);
}
- return toStatus(holder->get()->provision(String8(provisionString.c_str())));
+ return toStatus(holder->provision(String8(provisionString.c_str())));
}
Return<Status> CasImpl::refreshEntitlements(
int32_t refreshType,
const HidlCasData& refreshData) {
ALOGV("%s", __FUNCTION__);
- sp<PluginHolder> holder = mPluginHolder;
- if (holder == NULL) {
+ std::shared_ptr<CasPlugin> holder = std::atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
return toStatus(INVALID_OPERATION);
}
- status_t err = holder->get()->refreshEntitlements(refreshType, refreshData);
+ status_t err = holder->refreshEntitlements(refreshType, refreshData);
return toStatus(err);
}
Return<Status> CasImpl::release() {
- ALOGV("%s: plugin=%p", __FUNCTION__,
- mPluginHolder != NULL ? mPluginHolder->get() : NULL);
- mPluginHolder.clear();
+ ALOGV("%s: plugin=%p", __FUNCTION__, mPluginHolder.get());
+
+ std::shared_ptr<CasPlugin> holder(nullptr);
+ std::atomic_store(&mPluginHolder, holder);
+
return Status::OK;
}
diff --git a/cas/1.0/default/CasImpl.h b/cas/1.0/default/CasImpl.h
index 841d64e..d792838 100644
--- a/cas/1.0/default/CasImpl.h
+++ b/cas/1.0/default/CasImpl.h
@@ -88,7 +88,7 @@
private:
struct PluginHolder;
sp<SharedLibrary> mLibrary;
- sp<PluginHolder> mPluginHolder;
+ std::shared_ptr<CasPlugin> mPluginHolder;
sp<ICasListener> mListener;
DISALLOW_EVIL_CONSTRUCTORS(CasImpl);
diff --git a/cas/1.0/default/DescramblerImpl.cpp b/cas/1.0/default/DescramblerImpl.cpp
index 36699ba..1f89933 100644
--- a/cas/1.0/default/DescramblerImpl.cpp
+++ b/cas/1.0/default/DescramblerImpl.cpp
@@ -50,12 +50,12 @@
DescramblerImpl::DescramblerImpl(
const sp<SharedLibrary>& library, DescramblerPlugin *plugin) :
- mLibrary(library), mPlugin(plugin) {
- ALOGV("CTOR: mPlugin=%p", mPlugin);
+ mLibrary(library), mPluginHolder(plugin) {
+ ALOGV("CTOR: plugin=%p", mPluginHolder.get());
}
DescramblerImpl::~DescramblerImpl() {
- ALOGV("DTOR: mPlugin=%p", mPlugin);
+ ALOGV("DTOR: plugin=%p", mPluginHolder.get());
release();
}
@@ -63,12 +63,22 @@
ALOGV("%s: sessionId=%s", __FUNCTION__,
sessionIdToString(sessionId).string());
- return toStatus(mPlugin->setMediaCasSession(sessionId));
+ std::shared_ptr<DescramblerPlugin> holder = std::atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return toStatus(INVALID_OPERATION);
+ }
+
+ return toStatus(holder->setMediaCasSession(sessionId));
}
Return<bool> DescramblerImpl::requiresSecureDecoderComponent(
const hidl_string& mime) {
- return mPlugin->requiresSecureDecoderComponent(String8(mime.c_str()));
+ std::shared_ptr<DescramblerPlugin> holder = std::atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ return false;
+ }
+
+ return holder->requiresSecureDecoderComponent(String8(mime.c_str()));
}
static inline bool validateRangeForSize(
@@ -86,12 +96,23 @@
descramble_cb _hidl_cb) {
ALOGV("%s", __FUNCTION__);
+ // Get a local copy of the shared_ptr for the plugin. Note that before
+ // calling the HIDL callback, this shared_ptr must be manually reset,
+ // since the client side could proceed as soon as the callback is called
+ // without waiting for this method to go out of scope.
+ std::shared_ptr<DescramblerPlugin> holder = std::atomic_load(&mPluginHolder);
+ if (holder.get() == nullptr) {
+ _hidl_cb(toStatus(INVALID_OPERATION), 0, NULL);
+ return Void();
+ }
+
sp<IMemory> srcMem = mapMemory(srcBuffer.heapBase);
// Validate if the offset and size in the SharedBuffer is consistent with the
// mapped ashmem, since the offset and size is controlled by client.
if (srcMem == NULL) {
ALOGE("Failed to map src buffer.");
+ holder.reset();
_hidl_cb(toStatus(BAD_VALUE), 0, NULL);
return Void();
}
@@ -100,6 +121,7 @@
ALOGE("Invalid src buffer range: offset %llu, size %llu, srcMem size %llu",
srcBuffer.offset, srcBuffer.size, (uint64_t)srcMem->getSize());
android_errorWriteLog(0x534e4554, "67962232");
+ holder.reset();
_hidl_cb(toStatus(BAD_VALUE), 0, NULL);
return Void();
}
@@ -117,6 +139,7 @@
"srcOffset %llu, totalBytesInSubSamples %llu, srcBuffer size %llu",
srcOffset, totalBytesInSubSamples, srcBuffer.size);
android_errorWriteLog(0x534e4554, "67962232");
+ holder.reset();
_hidl_cb(toStatus(BAD_VALUE), 0, NULL);
return Void();
}
@@ -135,6 +158,7 @@
"dstOffset %llu, totalBytesInSubSamples %llu, srcBuffer size %llu",
dstOffset, totalBytesInSubSamples, srcBuffer.size);
android_errorWriteLog(0x534e4554, "67962232");
+ holder.reset();
_hidl_cb(toStatus(BAD_VALUE), 0, NULL);
return Void();
}
@@ -146,7 +170,7 @@
// Casting hidl SubSample to DescramblerPlugin::SubSample, but need
// to ensure structs are actually idential
- int32_t result = mPlugin->descramble(
+ int32_t result = holder->descramble(
dstBuffer.type != BufferType::SHARED_MEMORY,
(DescramblerPlugin::ScramblingControl)scramblingControl,
subSamples.size(),
@@ -157,17 +181,17 @@
dstOffset,
NULL);
+ holder.reset();
_hidl_cb(toStatus(result >= 0 ? OK : result), result, NULL);
return Void();
}
Return<Status> DescramblerImpl::release() {
- ALOGV("%s: mPlugin=%p", __FUNCTION__, mPlugin);
+ ALOGV("%s: plugin=%p", __FUNCTION__, mPluginHolder.get());
- if (mPlugin != NULL) {
- delete mPlugin;
- mPlugin = NULL;
- }
+ std::shared_ptr<DescramblerPlugin> holder(nullptr);
+ std::atomic_store(&mPluginHolder, holder);
+
return Status::OK;
}
diff --git a/cas/1.0/default/DescramblerImpl.h b/cas/1.0/default/DescramblerImpl.h
index d3b146e..305f115 100644
--- a/cas/1.0/default/DescramblerImpl.h
+++ b/cas/1.0/default/DescramblerImpl.h
@@ -55,7 +55,7 @@
private:
sp<SharedLibrary> mLibrary;
- DescramblerPlugin *mPlugin;
+ std::shared_ptr<DescramblerPlugin> mPluginHolder;
DISALLOW_EVIL_CONSTRUCTORS(DescramblerImpl);
};
diff --git a/configstore/1.0/default/seccomp_policy/configstore@1.0-arm64.policy b/configstore/1.0/default/seccomp_policy/configstore@1.0-arm64.policy
index f2dd892..d523a1a 100644
--- a/configstore/1.0/default/seccomp_policy/configstore@1.0-arm64.policy
+++ b/configstore/1.0/default/seccomp_policy/configstore@1.0-arm64.policy
@@ -42,6 +42,7 @@
rt_sigreturn: 1
getrlimit: 1
madvise: 1
+getdents64: 1
clock_gettime: 1
# used during process crash by crash_dump to dump process info
diff --git a/current.txt b/current.txt
index 5aa6259..0d79272 100644
--- a/current.txt
+++ b/current.txt
@@ -258,7 +258,7 @@
fb92e2b40f8e9d494e8fd3b4ac18499a3216342e7cff160714c3bbf3660b6e79 android.hardware.gnss@1.0::IGnssConfiguration
251594ea9b27447bfa005ebd806e58fb0ae4aad84a69938129c9800ec0c64eda android.hardware.gnss@1.0::IGnssMeasurementCallback
4e7169919d24fbe5573e5bcd683d0bd7abf553a4e6c34c41f9dfc1e12050db07 android.hardware.gnss@1.0::IGnssNavigationMessageCallback
-08ae9fc24f21f809e9b8501dfbc803662fcd6a8d8e1fb71d9dd7c0c4c6f5d556 android.hardware.neuralnetworks@1.0::types
+1488db5ffb8a7979488d1084761aab8bca2f59bc9a02d75cdefc296afeaf591b android.hardware.neuralnetworks@1.0::types
d4840db8efabdf1e4b344fc981cd36e5fe81a39aff6e199f6d06c1c8da413efd android.hardware.radio@1.0::types
b280c4704dfcc548a9bf127b59b7c3578f460c50cce70a06b66fe0df8b27cff0 android.hardware.wifi@1.0::types
diff --git a/health/2.0/README b/health/2.0/README
index 2281f98..11e6a7a 100644
--- a/health/2.0/README
+++ b/health/2.0/README
@@ -71,6 +71,7 @@
class hal
user system
group system
+ file /dev/kmsg w
5. Create device/<manufacturer>/<device>/health/HealthService.cpp:
diff --git a/neuralnetworks/1.0/types.hal b/neuralnetworks/1.0/types.hal
index c97a00b..a9c91cd 100644
--- a/neuralnetworks/1.0/types.hal
+++ b/neuralnetworks/1.0/types.hal
@@ -44,7 +44,7 @@
*
* Attached to this tensor are two numbers that can be used to convert the
* 8 bit integer to the real value and vice versa. These two numbers are:
- * - scale: a 32 bit floating point value
+ * - scale: a 32 bit floating point value greater than zero
* - zero_value: a 32 bit integer
*
* The formula is: