Make error handling kill context activity. Add parameter validation.

bug 10427951

Change-Id: I4abba969e34903265b84ee88d6a90bc9b9df5481
diff --git a/cpp/Allocation.cpp b/cpp/Allocation.cpp
index f05b005..9727a6e 100644
--- a/cpp/Allocation.cpp
+++ b/cpp/Allocation.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2012 The Android Open Source Project
+ * Copyright (C) 2013 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -15,6 +15,7 @@
  */
 
 #include "RenderScript.h"
+#include "rsCppInternal.h"
 
 using namespace android;
 using namespace RSC;
@@ -139,71 +140,77 @@
     case RS_ALLOCATION_USAGE_GRAPHICS_CONSTANTS:
     case RS_ALLOCATION_USAGE_GRAPHICS_TEXTURE:
     case RS_ALLOCATION_USAGE_GRAPHICS_VERTEX:
+    case RS_ALLOCATION_USAGE_SHARED:
         break;
     default:
-        ALOGE("Source must be exactly one usage type.");
+        mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Source must be exactly one usage type.");
+        return;
     }
-    RS::dispatch->AllocationSyncAll(mRS->getContext(), getIDSafe(), srcLocation);
+    tryDispatch(mRS, RS::dispatch->AllocationSyncAll(mRS->getContext(), getIDSafe(), srcLocation));
 }
 
 void Allocation::ioSendOutput() {
 #ifndef RS_COMPATIBILITY_LIB
     if ((mUsage & RS_ALLOCATION_USAGE_IO_OUTPUT) == 0) {
-        ALOGE("Can only send buffer if IO_OUTPUT usage specified.");
+        mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Can only send buffer if IO_OUTPUT usage specified.");
+        return;
     }
-    RS::dispatch->AllocationIoSend(mRS->getContext(), getID());
+    tryDispatch(mRS, RS::dispatch->AllocationIoSend(mRS->getContext(), getID()));
 #endif
 }
 
 void Allocation::ioGetInput() {
 #ifndef RS_COMPATIBILITY_LIB
     if ((mUsage & RS_ALLOCATION_USAGE_IO_INPUT) == 0) {
-        ALOGE("Can only send buffer if IO_OUTPUT usage specified.");
+        mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Can only send buffer if IO_OUTPUT usage specified.");
+        return;
     }
-    RS::dispatch->AllocationIoReceive(mRS->getContext(), getID());
+    tryDispatch(mRS, RS::dispatch->AllocationIoReceive(mRS->getContext(), getID()));
 #endif
 }
 
 void Allocation::generateMipmaps() {
-    RS::dispatch->AllocationGenerateMipmaps(mRS->getContext(), getID());
+    tryDispatch(mRS, RS::dispatch->AllocationGenerateMipmaps(mRS->getContext(), getID()));
 }
 
 void Allocation::copy1DRangeFrom(uint32_t off, size_t count, const void *data) {
 
     if(count < 1) {
-        ALOGE("Count must be >= 1.");
+        mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Count must be >= 1.");
         return;
     }
     if((off + count) > mCurrentCount) {
         ALOGE("Overflow, Available count %zu, got %zu at offset %zu.", mCurrentCount, count, off);
+        mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Invalid copy specified");
         return;
     }
 
-    RS::dispatch->Allocation1DData(mRS->getContext(), getIDSafe(), off, mSelectedLOD, count, data,
-                                   count * mType->getElement()->getSizeBytes());
+    tryDispatch(mRS, RS::dispatch->Allocation1DData(mRS->getContext(), getIDSafe(), off, mSelectedLOD,
+                                                    count, data, count * mType->getElement()->getSizeBytes()));
 }
 
 void Allocation::copy1DRangeTo(uint32_t off, size_t count, void *data) {
     if(count < 1) {
-        ALOGE("Count must be >= 1.");
+        mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Count must be >= 1.");
         return;
     }
     if((off + count) > mCurrentCount) {
         ALOGE("Overflow, Available count %zu, got %zu at offset %zu.", mCurrentCount, count, off);
+        mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Invalid copy specified");
         return;
     }
 
-    RS::dispatch->Allocation1DRead(mRS->getContext(), getIDSafe(), off, mSelectedLOD, count, data,
-                                   count * mType->getElement()->getSizeBytes());
+    tryDispatch(mRS, RS::dispatch->Allocation1DRead(mRS->getContext(), getIDSafe(), off, mSelectedLOD,
+                                                    count, data, count * mType->getElement()->getSizeBytes()));
 }
 
 void Allocation::copy1DRangeFrom(uint32_t off, size_t count, sp<const Allocation> data,
                                  uint32_t dataOff) {
 
-    RS::dispatch->AllocationCopy2DRange(mRS->getContext(), getIDSafe(), off, 0,
-                                        mSelectedLOD, mSelectedFace,
-                                        count, 1, data->getIDSafe(), dataOff, 0,
-                                        data->mSelectedLOD, data->mSelectedFace);
+    tryDispatch(mRS, RS::dispatch->AllocationCopy2DRange(mRS->getContext(), getIDSafe(), off, 0,
+                                                         mSelectedLOD, mSelectedFace,
+                                                         count, 1, data->getIDSafe(), dataOff, 0,
+                                                         data->mSelectedLOD, data->mSelectedFace));
 }
 
 void Allocation::copy1DFrom(const void* data) {
@@ -220,7 +227,7 @@
 
     } else {
         if (((xoff + w) > mCurrentDimX) || ((yoff + h) > mCurrentDimY)) {
-            ALOGE("Updated region larger than allocation.");
+            mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Updated region larger than allocation.");
         }
     }
 }
@@ -228,31 +235,36 @@
 void Allocation::copy2DRangeFrom(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
                                  const void *data) {
     validate2DRange(xoff, yoff, w, h);
-    RS::dispatch->Allocation2DData(mRS->getContext(), getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace,
-                                   w, h, data, w * h * mType->getElement()->getSizeBytes(), w * mType->getElement()->getSizeBytes());
+    tryDispatch(mRS, RS::dispatch->Allocation2DData(mRS->getContext(), getIDSafe(), xoff,
+                                                    yoff, mSelectedLOD, mSelectedFace,
+                                                    w, h, data, w * h * mType->getElement()->getSizeBytes(),
+                                                    w * mType->getElement()->getSizeBytes()));
 }
 
 void Allocation::copy2DRangeFrom(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
                                  sp<const Allocation> data, uint32_t dataXoff, uint32_t dataYoff) {
     validate2DRange(xoff, yoff, w, h);
-    RS::dispatch->AllocationCopy2DRange(mRS->getContext(), getIDSafe(), xoff, yoff,
-                                        mSelectedLOD, mSelectedFace,
-                                        w, h, data->getIDSafe(), dataXoff, dataYoff,
-                                        data->mSelectedLOD, data->mSelectedFace);
+    tryDispatch(mRS, RS::dispatch->AllocationCopy2DRange(mRS->getContext(), getIDSafe(), xoff, yoff,
+                                                         mSelectedLOD, mSelectedFace,
+                                                         w, h, data->getIDSafe(), dataXoff, dataYoff,
+                                                         data->mSelectedLOD, data->mSelectedFace));
 }
 
 void Allocation::copy2DRangeTo(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
                                void* data) {
     validate2DRange(xoff, yoff, w, h);
-    RS::dispatch->Allocation2DRead(mRS->getContext(), getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace,
-                                   w, h, data, w * h * mType->getElement()->getSizeBytes(), w * mType->getElement()->getSizeBytes());
+    tryDispatch(mRS, RS::dispatch->Allocation2DRead(mRS->getContext(), getIDSafe(), xoff, yoff,
+                                                    mSelectedLOD, mSelectedFace, w, h, data,
+                                                    w * h * mType->getElement()->getSizeBytes(),
+                                                    w * mType->getElement()->getSizeBytes()));
 }
 
 void Allocation::copy2DStridedFrom(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
                                    const void *data, size_t stride) {
     validate2DRange(xoff, yoff, w, h);
-    RS::dispatch->Allocation2DData(mRS->getContext(), getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace,
-                                   w, h, data, w * h * mType->getElement()->getSizeBytes(), stride);
+    tryDispatch(mRS, RS::dispatch->Allocation2DData(mRS->getContext(), getIDSafe(), xoff, yoff,
+                                                    mSelectedLOD, mSelectedFace, w, h, data,
+                                                    w * h * mType->getElement()->getSizeBytes(), stride));
 }
 
 void Allocation::copy2DStridedFrom(const void* data, size_t stride) {
@@ -262,8 +274,9 @@
 void Allocation::copy2DStridedTo(uint32_t xoff, uint32_t yoff, uint32_t w, uint32_t h,
                                  void *data, size_t stride) {
     validate2DRange(xoff, yoff, w, h);
-    RS::dispatch->Allocation2DRead(mRS->getContext(), getIDSafe(), xoff, yoff, mSelectedLOD, mSelectedFace,
-                                   w, h, data, w * h * mType->getElement()->getSizeBytes(), stride);
+    tryDispatch(mRS, RS::dispatch->Allocation2DRead(mRS->getContext(), getIDSafe(), xoff, yoff,
+                                                    mSelectedLOD, mSelectedFace, w, h, data,
+                                                    w * h * mType->getElement()->getSizeBytes(), stride));
 }
 
 void Allocation::copy2DStridedTo(void* data, size_t stride) {
@@ -272,9 +285,12 @@
 
 sp<Allocation> Allocation::createTyped(sp<RS> rs, sp<const Type> type,
                                     RsAllocationMipmapControl mips, uint32_t usage) {
-    void *id = RS::dispatch->AllocationCreateTyped(rs->getContext(), type->getID(), mips, usage, 0);
+    void *id = 0;
+    if (rs->getError() == RS_SUCCESS) {
+        id = RS::dispatch->AllocationCreateTyped(rs->getContext(), type->getID(), mips, usage, 0);
+    }
     if (id == 0) {
-        ALOGE("Allocation creation failed.");
+        rs->throwError(RS_ERROR_RUNTIME_ERROR, "Allocation creation failed");
         return NULL;
     }
     return new Allocation(id, rs, type, usage);
@@ -283,10 +299,14 @@
 sp<Allocation> Allocation::createTyped(sp<RS> rs, sp<const Type> type,
                                     RsAllocationMipmapControl mips, uint32_t usage,
                                     void *pointer) {
-    void *id = RS::dispatch->AllocationCreateTyped(rs->getContext(), type->getID(), mips, usage,
-                                                   (uintptr_t)pointer);
+    void *id = 0;
+    if (rs->getError() == RS_SUCCESS) {
+        id = RS::dispatch->AllocationCreateTyped(rs->getContext(), type->getID(), mips, usage,
+                                                 (uintptr_t)pointer);
+    }
     if (id == 0) {
-        ALOGE("Allocation creation failed.");
+        rs->throwError(RS_ERROR_RUNTIME_ERROR, "Allocation creation failed");
+        return NULL;
     }
     return new Allocation(id, rs, type, usage);
 }
diff --git a/cpp/Element.cpp b/cpp/Element.cpp
index df7b5a0..d685595 100644
--- a/cpp/Element.cpp
+++ b/cpp/Element.cpp
@@ -331,7 +331,7 @@
     return new Element(id, rs, dt, dk, true, size);
 }
 
-bool Element::isCompatible(android::RSC::sp<const Element>e) {
+bool Element::isCompatible(android::RSC::sp<const Element>e) const {
     // Try strict BaseObj equality to start with.
     if (this == e.get()) {
         return true;
diff --git a/cpp/RenderScript.cpp b/cpp/RenderScript.cpp
index 561b58f..6ab2240 100644
--- a/cpp/RenderScript.cpp
+++ b/cpp/RenderScript.cpp
@@ -506,6 +506,10 @@
     }
 }
 
+RSError RS::getError() {
+    return mCurrentError;
+}
+
 
 void * RS::threadProc(void *vrsc) {
     RS *rs = static_cast<RS *>(vrsc);
diff --git a/cpp/Script.cpp b/cpp/Script.cpp
index 29fe12d..8e1af54 100644
--- a/cpp/Script.cpp
+++ b/cpp/Script.cpp
@@ -17,12 +17,13 @@
 #include <malloc.h>
 
 #include "RenderScript.h"
+#include "rsCppInternal.h"
 
 using namespace android;
 using namespace RSC;
 
 void Script::invoke(uint32_t slot, const void *v, size_t len) const {
-    RS::dispatch->ScriptInvokeV(mRS->getContext(), getID(), slot, v, len);
+    tryDispatch(mRS, RS::dispatch->ScriptInvokeV(mRS->getContext(), getID(), slot, v, len));
 }
 
 void Script::forEach(uint32_t slot, sp<const Allocation> ain, sp<const Allocation> aout,
@@ -32,7 +33,7 @@
     }
     void *in_id = BaseObj::getObjID(ain);
     void *out_id = BaseObj::getObjID(aout);
-    RS::dispatch->ScriptForEach(mRS->getContext(), getID(), slot, in_id, out_id, usr, usrLen, NULL, 0);
+    tryDispatch(mRS, RS::dispatch->ScriptForEach(mRS->getContext(), getID(), slot, in_id, out_id, usr, usrLen, NULL, 0));
 }
 
 
@@ -41,16 +42,16 @@
 
 
 void Script::bindAllocation(sp<Allocation> va, uint32_t slot) const {
-    RS::dispatch->ScriptBindAllocation(mRS->getContext(), getID(), BaseObj::getObjID(va), slot);
+    tryDispatch(mRS, RS::dispatch->ScriptBindAllocation(mRS->getContext(), getID(), BaseObj::getObjID(va), slot));
 }
 
 
 void Script::setVar(uint32_t index, sp<const BaseObj> o) const {
-    RS::dispatch->ScriptSetVarObj(mRS->getContext(), getID(), index, (o == NULL) ? 0 : o->getID());
+    tryDispatch(mRS, RS::dispatch->ScriptSetVarObj(mRS->getContext(), getID(), index, (o == NULL) ? 0 : o->getID()));
 }
 
 void Script::setVar(uint32_t index, const void *v, size_t len) const {
-    RS::dispatch->ScriptSetVarV(mRS->getContext(), getID(), index, v, len);
+    tryDispatch(mRS, RS::dispatch->ScriptSetVarV(mRS->getContext(), getID(), index, v, len));
 }
 
 void Script::FieldBase::init(sp<RS> rs, uint32_t dimx, uint32_t usages) {
diff --git a/cpp/ScriptIntrinsics.cpp b/cpp/ScriptIntrinsics.cpp
index ab24952..e4bf907 100644
--- a/cpp/ScriptIntrinsics.cpp
+++ b/cpp/ScriptIntrinsics.cpp
@@ -24,6 +24,7 @@
 ScriptIntrinsic::ScriptIntrinsic(sp<RS> rs, int id, sp<const Element> e)
     : Script(NULL, rs) {
     mID = RS::dispatch->ScriptIntrinsicCreate(rs->getContext(), id, e->getID());
+    mElement = e;
 }
 
 ScriptIntrinsic::~ScriptIntrinsic() {
@@ -31,6 +32,10 @@
 }
 
 sp<ScriptIntrinsic3DLUT> ScriptIntrinsic3DLUT::create(sp<RS> rs, sp<const Element> e) {
+    if (e->isCompatible(Element::U8_4(rs)) == false) {
+        rs->throwError(RS_ERROR_INVALID_ELEMENT, "Element not supported for intrinsic");
+        return NULL;
+    }
     return new ScriptIntrinsic3DLUT(rs, e);
 }
 
@@ -39,13 +44,32 @@
 
 }
 void ScriptIntrinsic3DLUT::forEach(sp<Allocation> ain, sp<Allocation> aout) {
+    if (ain->getType()->getElement()->isCompatible(mElement) == false ||
+        aout->getType()->getElement()->isCompatible(mElement) == false) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "3DLUT forEach element mismatch");
+        return;
+    }
     Script::forEach(0, ain, aout, NULL, 0);
 }
 void ScriptIntrinsic3DLUT::setLUT(sp<Allocation> lut) {
+    sp<const Type> t = lut->getType();
+    if (!t->getElement()->isCompatible(mElement)) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "setLUT element does not match");
+        return;
+    }
+    if (t->getZ() == 0) {
+        mRS->throwError(RS_ERROR_INVALID_PARAMETER, "setLUT Allocation must be 3D");
+        return;
+    }
+
     Script::setVar(0, lut);
 }
 
 sp<ScriptIntrinsicBlend> ScriptIntrinsicBlend::create(sp<RS> rs, sp<const Element> e) {
+    if (e->isCompatible(Element::U8_4(rs)) == false) {
+        rs->throwError(RS_ERROR_INVALID_ELEMENT, "Element not supported for intrinsic");
+        return NULL;
+    }
     return new ScriptIntrinsicBlend(rs, e);
 }
 
@@ -54,64 +78,124 @@
 }
 
 void ScriptIntrinsicBlend::blendClear(sp<Allocation> in, sp<Allocation> out) {
+    if (in->getType()->getElement()->isCompatible(mElement) == false ||
+        out->getType()->getElement()->isCompatible(mElement) == false) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
+    }
     Script::forEach(0, in, out, NULL, 0);
 }
 
 void ScriptIntrinsicBlend::blendSrc(sp<Allocation> in, sp<Allocation> out) {
+    if (in->getType()->getElement()->isCompatible(mElement) == false ||
+        out->getType()->getElement()->isCompatible(mElement) == false) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
+    }
     Script::forEach(1, in, out, NULL, 0);
 }
 
 void ScriptIntrinsicBlend::blendDst(sp<Allocation> in, sp<Allocation> out) {
+    if (in->getType()->getElement()->isCompatible(mElement) == false ||
+        out->getType()->getElement()->isCompatible(mElement) == false) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
+    }
     Script::forEach(2, in, out, NULL, 0);
 }
 
 void ScriptIntrinsicBlend::blendSrcOver(sp<Allocation> in, sp<Allocation> out) {
+    if (in->getType()->getElement()->isCompatible(mElement) == false ||
+        out->getType()->getElement()->isCompatible(mElement) == false) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
+    }
     Script::forEach(3, in, out, NULL, 0);
 }
 
 void ScriptIntrinsicBlend::blendDstOver(sp<Allocation> in, sp<Allocation> out) {
+    if (in->getType()->getElement()->isCompatible(mElement) == false ||
+        out->getType()->getElement()->isCompatible(mElement) == false) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
+    }
     Script::forEach(4, in, out, NULL, 0);
 }
 
 void ScriptIntrinsicBlend::blendSrcIn(sp<Allocation> in, sp<Allocation> out) {
+    if (in->getType()->getElement()->isCompatible(mElement) == false ||
+        out->getType()->getElement()->isCompatible(mElement) == false) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
+    }
     Script::forEach(5, in, out, NULL, 0);
 }
 
 void ScriptIntrinsicBlend::blendDstIn(sp<Allocation> in, sp<Allocation> out) {
+    if (in->getType()->getElement()->isCompatible(mElement) == false ||
+        out->getType()->getElement()->isCompatible(mElement) == false) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
+    }
     Script::forEach(6, in, out, NULL, 0);
 }
 
 void ScriptIntrinsicBlend::blendSrcOut(sp<Allocation> in, sp<Allocation> out) {
+    if (in->getType()->getElement()->isCompatible(mElement) == false ||
+        out->getType()->getElement()->isCompatible(mElement) == false) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
+    }
     Script::forEach(7, in, out, NULL, 0);
 }
 
 void ScriptIntrinsicBlend::blendDstOut(sp<Allocation> in, sp<Allocation> out) {
+    if (in->getType()->getElement()->isCompatible(mElement) == false ||
+        out->getType()->getElement()->isCompatible(mElement) == false) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
+    }
     Script::forEach(8, in, out, NULL, 0);
 }
 
 void ScriptIntrinsicBlend::blendSrcAtop(sp<Allocation> in, sp<Allocation> out) {
+    if (in->getType()->getElement()->isCompatible(mElement) == false ||
+        out->getType()->getElement()->isCompatible(mElement) == false) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
+    }
     Script::forEach(9, in, out, NULL, 0);
 }
 
 void ScriptIntrinsicBlend::blendDstAtop(sp<Allocation> in, sp<Allocation> out) {
+    if (in->getType()->getElement()->isCompatible(mElement) == false ||
+        out->getType()->getElement()->isCompatible(mElement) == false) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
+    }
     Script::forEach(10, in, out, NULL, 0);
 }
 
 void ScriptIntrinsicBlend::blendXor(sp<Allocation> in, sp<Allocation> out) {
+    if (in->getType()->getElement()->isCompatible(mElement) == false ||
+        out->getType()->getElement()->isCompatible(mElement) == false) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
+    }
     Script::forEach(11, in, out, NULL, 0);
 }
 
 // Numbering jumps here
 void ScriptIntrinsicBlend::blendMultiply(sp<Allocation> in, sp<Allocation> out) {
+    if (in->getType()->getElement()->isCompatible(mElement) == false ||
+        out->getType()->getElement()->isCompatible(mElement) == false) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
+    }
     Script::forEach(14, in, out, NULL, 0);
 }
 
 // Numbering jumps here
 void ScriptIntrinsicBlend::blendAdd(sp<Allocation> in, sp<Allocation> out) {
+    if (in->getType()->getElement()->isCompatible(mElement) == false ||
+        out->getType()->getElement()->isCompatible(mElement) == false) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
+    }
     Script::forEach(34, in, out, NULL, 0);
 }
 
 void ScriptIntrinsicBlend::blendSubtract(sp<Allocation> in, sp<Allocation> out) {
+    if (in->getType()->getElement()->isCompatible(mElement) == false ||
+        out->getType()->getElement()->isCompatible(mElement) == false) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blend");
+    }
     Script::forEach(35, in, out, NULL, 0);
 }
 
@@ -119,6 +203,11 @@
 
 
 sp<ScriptIntrinsicBlur> ScriptIntrinsicBlur::create(sp<RS> rs, sp<const Element> e) {
+    if ((e->isCompatible(Element::U8_4(rs)) == false) &&
+        (e->isCompatible(Element::U8(rs)) == false)) {
+        rs->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blur");
+        return NULL;
+    }
     return new ScriptIntrinsicBlur(rs, e);
 }
 
@@ -128,15 +217,27 @@
 }
 
 void ScriptIntrinsicBlur::setInput(sp<Allocation> in) {
+    if (in->getType()->getElement()->isCompatible(mElement) == false) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blur input");
+        return;
+    }
     Script::setVar(1, in);
 }
 
 void ScriptIntrinsicBlur::forEach(sp<Allocation> out) {
+    if (out->getType()->getElement()->isCompatible(mElement) == false) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element in blur output");
+        return;
+    }
     Script::forEach(0, NULL, out, NULL, 0);
 }
 
 void ScriptIntrinsicBlur::setRadius(float radius) {
-    Script::setVar(0, &radius, sizeof(float));
+    if (radius > 0.f && radius <= 25.f) {
+        Script::setVar(0, &radius, sizeof(float));
+    } else {
+        mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Blur radius out of 0-25 pixel bound");
+    }
 }
 
 
@@ -151,9 +252,36 @@
 }
 
 void ScriptIntrinsicColorMatrix::forEach(sp<Allocation> in, sp<Allocation> out) {
+    if (!(in->getType()->getElement()->isCompatible(Element::U8(mRS))) &&
+        !(in->getType()->getElement()->isCompatible(Element::U8_2(mRS))) &&
+        !(in->getType()->getElement()->isCompatible(Element::U8_3(mRS))) &&
+        !(in->getType()->getElement()->isCompatible(Element::U8_4(mRS))) &&
+        !(in->getType()->getElement()->isCompatible(Element::F32(mRS))) &&
+        !(in->getType()->getElement()->isCompatible(Element::F32_2(mRS))) &&
+        !(in->getType()->getElement()->isCompatible(Element::F32_3(mRS))) &&
+        !(in->getType()->getElement()->isCompatible(Element::F32_4(mRS)))) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element for ColorMatrix");
+        return;
+    }
+
+    if (!(out->getType()->getElement()->isCompatible(Element::U8(mRS))) &&
+        !(out->getType()->getElement()->isCompatible(Element::U8_2(mRS))) &&
+        !(out->getType()->getElement()->isCompatible(Element::U8_3(mRS))) &&
+        !(out->getType()->getElement()->isCompatible(Element::U8_4(mRS))) &&
+        !(out->getType()->getElement()->isCompatible(Element::F32(mRS))) &&
+        !(out->getType()->getElement()->isCompatible(Element::F32_2(mRS))) &&
+        !(out->getType()->getElement()->isCompatible(Element::F32_3(mRS))) &&
+        !(out->getType()->getElement()->isCompatible(Element::F32_4(mRS)))) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element for ColorMatrix");
+        return;
+    }
+
     Script::forEach(0, in, out, NULL, 0);
 }
 
+void ScriptIntrinsicColorMatrix::setAdd(float* add) {
+    Script::setVar(1, (void*)add, sizeof(float) * 4);
+}
 
 void ScriptIntrinsicColorMatrix::setColorMatrix3(float* m) {
     Script::setVar(0, (void*)m, sizeof(float) * 9);
@@ -185,6 +313,18 @@
 
 
 sp<ScriptIntrinsicConvolve3x3> ScriptIntrinsicConvolve3x3::create(sp<RS> rs, sp<const Element> e) {
+    if (!(e->isCompatible(Element::U8(rs))) &&
+        !(e->isCompatible(Element::U8_2(rs))) &&
+        !(e->isCompatible(Element::U8_3(rs))) &&
+        !(e->isCompatible(Element::U8_4(rs))) &&
+        !(e->isCompatible(Element::F32(rs))) &&
+        !(e->isCompatible(Element::F32_2(rs))) &&
+        !(e->isCompatible(Element::F32_3(rs))) &&
+        !(e->isCompatible(Element::F32_4(rs)))) {
+        rs->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element for Convolve3x3");
+        return NULL;
+    }
+
     return new ScriptIntrinsicConvolve3x3(rs, e);
 }
 
@@ -194,10 +334,18 @@
 }
 
 void ScriptIntrinsicConvolve3x3::setInput(sp<Allocation> in) {
+    if (!(in->getType()->getElement()->isCompatible(mElement))) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Element mismatch in Convolve3x3");
+        return;
+    }
     Script::setVar(1, in);
 }
 
 void ScriptIntrinsicConvolve3x3::forEach(sp<Allocation> out) {
+    if (!(out->getType()->getElement()->isCompatible(mElement))) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Element mismatch in Convolve3x3");
+        return;
+    }
     Script::forEach(0, NULL, out, NULL, 0);
 }
 
@@ -206,6 +354,18 @@
 }
 
 sp<ScriptIntrinsicConvolve5x5> ScriptIntrinsicConvolve5x5::create(sp<RS> rs, sp<const Element> e) {
+    if (!(e->isCompatible(Element::U8(rs))) &&
+        !(e->isCompatible(Element::U8_2(rs))) &&
+        !(e->isCompatible(Element::U8_3(rs))) &&
+        !(e->isCompatible(Element::U8_4(rs))) &&
+        !(e->isCompatible(Element::F32(rs))) &&
+        !(e->isCompatible(Element::F32_2(rs))) &&
+        !(e->isCompatible(Element::F32_3(rs))) &&
+        !(e->isCompatible(Element::F32_4(rs)))) {
+        rs->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element for Convolve5x5");
+        return NULL;
+    }
+
     return new ScriptIntrinsicConvolve5x5(rs, e);
 }
 
@@ -215,10 +375,19 @@
 }
 
 void ScriptIntrinsicConvolve5x5::setInput(sp<Allocation> in) {
+    if (!(in->getType()->getElement()->isCompatible(mElement))) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Element mismatch in Convolve5x5 input");
+        return;
+    }
     Script::setVar(1, in);
 }
 
 void ScriptIntrinsicConvolve5x5::forEach(sp<Allocation> out) {
+    if (!(out->getType()->getElement()->isCompatible(mElement))) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Element mismatch in Convolve5x5 output");
+        return;
+    }
+
     Script::forEach(0, NULL, out, NULL, 0);
 }
 
@@ -226,8 +395,8 @@
     Script::setVar(0, (void*)v, sizeof(float) * 25);
 }
 
-sp<ScriptIntrinsicHistogram> ScriptIntrinsicHistogram::create(sp<RS> rs, sp<const Element> e) {
-    return new ScriptIntrinsicHistogram(rs, e);
+sp<ScriptIntrinsicHistogram> ScriptIntrinsicHistogram::create(sp<RS> rs) {
+    return new ScriptIntrinsicHistogram(rs, NULL);
 }
 
 ScriptIntrinsicHistogram::ScriptIntrinsicHistogram(sp<RS> rs, sp<const Element> e)
@@ -235,8 +404,27 @@
 
 }
 
-void ScriptIntrinsicHistogram::setOutput(sp<Allocation> aout) {
-    Script::setVar(1, aout);
+void ScriptIntrinsicHistogram::setOutput(sp<Allocation> out) {
+    if (!(out->getType()->getElement()->isCompatible(Element::U32(mRS))) &&
+        !(out->getType()->getElement()->isCompatible(Element::U32_2(mRS))) &&
+        !(out->getType()->getElement()->isCompatible(Element::U32_3(mRS))) &&
+        !(out->getType()->getElement()->isCompatible(Element::U32_4(mRS))) &&
+        !(out->getType()->getElement()->isCompatible(Element::I32(mRS))) &&
+        !(out->getType()->getElement()->isCompatible(Element::I32_2(mRS))) &&
+        !(out->getType()->getElement()->isCompatible(Element::I32_3(mRS))) &&
+        !(out->getType()->getElement()->isCompatible(Element::I32_4(mRS)))) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element for Histogram output");
+        return;
+    }
+
+    if (out->getType()->getX() != 256 ||
+        out->getType()->getY() != 0 ||
+        out->getType()->hasMipmaps()) {
+        mRS->throwError(RS_ERROR_INVALID_PARAMETER, "Invalid Allocation type for Histogram output");
+        return;
+    }
+    mOut = out;
+    Script::setVar(1, out);
 }
 
 void ScriptIntrinsicHistogram::setDotCoefficients(float r, float g, float b, float a) {
@@ -257,15 +445,46 @@
 }
 
 void ScriptIntrinsicHistogram::forEach(sp<Allocation> ain) {
+    if (ain->getType()->getElement()->getVectorSize() <
+        mOut->getType()->getElement()->getVectorSize()) {
+        mRS->throwError(RS_ERROR_INVALID_PARAMETER,
+                        "Input vector size must be >= output vector size");
+        return;
+    }
+
+    if (!(ain->getType()->getElement()->isCompatible(Element::U8(mRS))) ||
+        !(ain->getType()->getElement()->isCompatible(Element::U8_4(mRS)))) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT,
+                        "Input allocation to Histogram must be U8 or U8_4");
+        return;
+    }
+
     Script::forEach(0, ain, NULL, NULL, 0);
 }
 
 
 void ScriptIntrinsicHistogram::forEach_dot(sp<Allocation> ain) {
+    if (mOut->getType()->getElement()->getVectorSize() != 1) {
+        mRS->throwError(RS_ERROR_INVALID_PARAMETER,
+                        "Output Histogram allocation must have vector size of 1 " \
+                        "when used with forEach_dot");
+        return;
+    }
+    if (!(ain->getType()->getElement()->isCompatible(Element::U8(mRS))) ||
+        !(ain->getType()->getElement()->isCompatible(Element::U8_4(mRS)))) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT,
+                        "Input allocation to Histogram must be U8 or U8_4");
+        return;
+    }
+
     Script::forEach(1, ain, NULL, NULL, 0);
 }
 
 sp<ScriptIntrinsicLUT> ScriptIntrinsicLUT::create(sp<RS> rs, sp<const Element> e) {
+    if (!(e->isCompatible(Element::U8_4(rs)))) {
+        rs->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element for LUT");
+        return NULL;
+    }
     return new ScriptIntrinsicLUT(rs, e);
 }
 
@@ -285,6 +504,11 @@
         LUT->copy1DFrom((void*)mCache);
         mDirty = false;
     }
+    if (!(ain->getType()->getElement()->isCompatible(Element::U8_4(mRS))) ||
+        !(aout->getType()->getElement()->isCompatible(Element::U8_4(mRS)))) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element for LUT");
+        return;
+    }
     Script::forEach(0, ain, aout, NULL, 0);
 
 }
@@ -300,18 +524,34 @@
 }
 
 void ScriptIntrinsicLUT::setRed(unsigned char base, unsigned char length, unsigned char* lutValues) {
+    if (base + length >= 256) {
+        mRS->throwError(RS_ERROR_INVALID_PARAMETER, "LUT out of range");
+        return;
+    }
     setTable(0, base, length, lutValues);
 }
 
 void ScriptIntrinsicLUT::setGreen(unsigned char base, unsigned char length, unsigned char* lutValues) {
+    if (base + length >= 256) {
+        mRS->throwError(RS_ERROR_INVALID_PARAMETER, "LUT out of range");
+        return;
+    }
     setTable(256, base, length, lutValues);
 }
 
 void ScriptIntrinsicLUT::setBlue(unsigned char base, unsigned char length, unsigned char* lutValues) {
+    if (base + length >= 256) {
+        mRS->throwError(RS_ERROR_INVALID_PARAMETER, "LUT out of range");
+        return;
+    }
     setTable(512, base, length, lutValues);
 }
 
 void ScriptIntrinsicLUT::setAlpha(unsigned char base, unsigned char length, unsigned char* lutValues) {
+    if (base + length >= 256) {
+        mRS->throwError(RS_ERROR_INVALID_PARAMETER, "LUT out of range");
+        return;
+    }
     setTable(768, base, length, lutValues);
 }
 
@@ -320,6 +560,10 @@
 }
 
 sp<ScriptIntrinsicYuvToRGB> ScriptIntrinsicYuvToRGB::create(sp<RS> rs, sp<const Element> e) {
+    if (!(e->isCompatible(Element::U8_4(rs)))) {
+        rs->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element for YuvToRGB");
+        return NULL;
+    }
     return new ScriptIntrinsicYuvToRGB(rs, e);
 }
 
@@ -329,9 +573,18 @@
 }
 
 void ScriptIntrinsicYuvToRGB::setInput(sp<Allocation> in) {
+    if (!(in->getType()->getElement()->isCompatible(mElement))) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element for input in YuvToRGB");
+        return;
+    }
     Script::setVar(0, in);
 }
 
 void ScriptIntrinsicYuvToRGB::forEach(sp<Allocation> out) {
+    if (!(out->getType()->getElement()->isCompatible(mElement))) {
+        mRS->throwError(RS_ERROR_INVALID_ELEMENT, "Invalid element for output in YuvToRGB");
+        return;
+    }
+
     Script::forEach(0, NULL, out, NULL, 0);
 }
diff --git a/cpp/rsCppInternal.h b/cpp/rsCppInternal.h
new file mode 100644
index 0000000..56ed5a3
--- /dev/null
+++ b/cpp/rsCppInternal.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2013 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ANDROID_RS_CPP_INTERNAL_H
+#define ANDROID_RS_CPP_INTERNAL_H
+
+#define tryDispatch(rs, dispatch)               \
+    if (rs->getError() == RS_SUCCESS) {         \
+        dispatch;                               \
+    }
+
+#endif
diff --git a/cpp/rsCppStructs.h b/cpp/rsCppStructs.h
index f6cb1dd..ef354f8 100644
--- a/cpp/rsCppStructs.h
+++ b/cpp/rsCppStructs.h
@@ -48,6 +48,7 @@
      RS_SUCCESS = 0,
      RS_ERROR_INVALID_PARAMETER = 1,
      RS_ERROR_RUNTIME_ERROR = 2,
+     RS_ERROR_INVALID_ELEMENT = 3,
      RS_ERROR_MAX = 9999
 
  };
@@ -67,6 +68,7 @@
     MessageHandlerFunc_t getMessageHandler() { return mMessageFunc; }
 
     void throwError(RSError error, const char *errMsg);
+    RSError getError();
 
     RsContext getContext() { return mContext; }
 
@@ -322,6 +324,10 @@
         return mSizeBytes;
     }
 
+    uint32_t getVectorSize() const {
+        return mVectorSize;
+    }
+
     static sp<const Element> BOOLEAN(sp<RS> rs);
     static sp<const Element> U8(sp<RS> rs);
     static sp<const Element> I8(sp<RS> rs);
@@ -389,7 +395,7 @@
     static sp<const Element> createUser(sp<RS> rs, RsDataType dt);
     static sp<const Element> createVector(sp<RS> rs, RsDataType dt, uint32_t size);
     static sp<const Element> createPixel(sp<RS> rs, RsDataType dt, RsDataKind dk);
-    bool isCompatible(sp<const Element>e);
+    bool isCompatible(sp<const Element>e) const;
 
     Element(void *id, sp<RS> rs,
             std::vector<sp<Element> > &elements,
@@ -669,6 +675,7 @@
 
 class ScriptIntrinsic : public Script {
  protected:
+    sp<const Element> mElement;
     ScriptIntrinsic(sp<RS> rs, int id, sp<const Element> e);
     virtual ~ScriptIntrinsic();
 };
@@ -720,6 +727,7 @@
  public:
     static sp<ScriptIntrinsicColorMatrix> create(sp<RS> rs, sp<const Element> e);
     void forEach(sp<Allocation> in, sp<Allocation> out);
+    void setAdd(float* add);
     void setColorMatrix3(float* m);
     void setColorMatrix4(float* m);
     void setGreyscale();
@@ -750,8 +758,9 @@
 class ScriptIntrinsicHistogram : public ScriptIntrinsic {
  private:
     ScriptIntrinsicHistogram(sp<RS> rs, sp<const Element> e);
+    sp<Allocation> mOut;
  public:
-    static sp<ScriptIntrinsicHistogram> create(sp<RS> rs, sp<const Element> e);
+    static sp<ScriptIntrinsicHistogram> create(sp<RS> rs);
     void setOutput(sp<Allocation> aout);
     void setDotCoefficients(float r, float g, float b, float a);
     void forEach(sp<Allocation> ain);