public void run() {
      // This function is a temporary solution.  The final solution will
      // used typed allocations where the message id is the type indicator.
      int[] rbuf = new int[16];
      mRS.nContextInitToClient(mRS.mContext);
      while (mRun) {
        rbuf[0] = 0;
        int msg = mRS.nContextPeekMessage(mRS.mContext, mAuxData);
        int size = mAuxData[1];
        int subID = mAuxData[0];

        if (msg == RS_MESSAGE_TO_CLIENT_USER) {
          if ((size >> 2) >= rbuf.length) {
            rbuf = new int[(size + 3) >> 2];
          }
          if (mRS.nContextGetUserMessage(mRS.mContext, rbuf) != RS_MESSAGE_TO_CLIENT_USER) {
            throw new RSDriverException("Error processing message from RenderScript.");
          }

          if (mRS.mMessageCallback != null) {
            mRS.mMessageCallback.mData = rbuf;
            mRS.mMessageCallback.mID = subID;
            mRS.mMessageCallback.mLength = size;
            mRS.mMessageCallback.run();
          } else {
            throw new RSInvalidStateException(
                "Received a message from the script with no message handler installed.");
          }
          continue;
        }

        if (msg == RS_MESSAGE_TO_CLIENT_ERROR) {
          String e = mRS.nContextGetErrorMessage(mRS.mContext);

          // Throw RSRuntimeException under the following conditions:
          //
          // 1) It is an unknown fatal error.
          // 2) It is a debug fatal error, and we are not in a
          //    debug context.
          // 3) It is a debug fatal error, and we do not have an
          //    error callback.
          if (subID >= RS_ERROR_FATAL_UNKNOWN
              || (subID >= RS_ERROR_FATAL_DEBUG
                  && (mRS.mContextType != ContextType.DEBUG || mRS.mErrorCallback == null))) {
            throw new RSRuntimeException("Fatal error " + subID + ", details: " + e);
          }

          if (mRS.mErrorCallback != null) {
            mRS.mErrorCallback.mErrorMessage = e;
            mRS.mErrorCallback.mErrorNum = subID;
            mRS.mErrorCallback.run();
          } else {
            android.util.Log.e(LOG_TAG, "non fatal RS error, " + e);
            // Do not throw here. In these cases, we do not have
            // a fatal error.
          }
          continue;
        }

        if (msg == RS_MESSAGE_TO_CLIENT_NEW_BUFFER) {
          if (mRS.nContextGetUserMessage(mRS.mContext, rbuf) != RS_MESSAGE_TO_CLIENT_NEW_BUFFER) {
            throw new RSDriverException("Error processing message from RenderScript.");
          }
          long bufferID = ((long) rbuf[1] << 32L) + ((long) rbuf[0] & 0xffffffffL);
          Allocation.sendBufferNotification(bufferID);
          continue;
        }

        // 2: teardown.
        // But we want to avoid starving other threads during
        // teardown by yielding until the next line in the destructor
        // can execute to set mRun = false
        try {
          sleep(1, 0);
        } catch (InterruptedException e) {
        }
      }
      // Log.d(LOG_TAG, "MessageThread exiting.");
    }