private synchronized boolean ensureWaitingThread() {
   if (mThreadCount <= mServicingCount) {
     try {
       // Only wait if no threads. Otherwise the lock on this object
       // will prevent threads from entering the exitThread method.
       startThread(mThreadCount == 0);
     } catch (NoThreadException e) {
       if (!e.isThreadPoolClosed()) {
         if (mThreadCount == 0) {
           uncaughtException(e);
           return false;
         }
       }
     } catch (InterruptedException e) {
       return false;
     } catch (Throwable e) {
       uncaughtException(e);
       return false;
     }
   }
   return true;
 }
    public void run() {
      boolean forceExit = false;
      TransactionQueueEvent event;

      while (true) {
        try {
          // allow event to be GC'd in case we wait() on next event
          event = null;

          // Phase 1: wait for a transaction
          try {
            if ((event = nextTransactionEvent()) == null) {
              // Go into idle mode.
              continue;
            }
          } catch (InterruptedException e) {
            forceExit = true;
            continue;
          }

          long enqueueTimestamp = event.getTimestampMillis();

          // Phase 2: spawn off a replacement thread
          try {
            startThread(false);
          } catch (NoThreadException e) {
            if (e.isThreadPoolClosed()) {
              forceExit = true;
              // Don't "continue" because the transaction must
              // still be serviced first.
            }
          } catch (InterruptedException e) {
            forceExit = true;
            // Don't "continue" because the transaction must
            // still be serviced first.
          } catch (Throwable e) {
            uncaughtException(e);
          } finally {
            // Only indicate that transaction has been dequeued
            // after a replacement thread has been created.
            // Queue time is more accurate this way because time
            // spent waiting for a thread is time spent not being
            // serviced.
            try {
              event = transactionDequeued(event);
            } catch (Throwable e) {
              uncaughtException(e);
            }
          }

          long serviceTimestamp = event.getTimestampMillis();

          // Phase 3: service the transaction
          long timeout = getTransactionTimeout();
          if (timeout >= 0 && (serviceTimestamp - enqueueTimestamp) >= timeout) {
            try {
              event.getTransaction().cancel();
            } finally {
              transactionExpired(event);
            }
          } else {
            try {
              event.getTransaction().service();
              transactionServiced(event);
            } catch (Throwable e) {
              uncaughtException(e);

              try {
                event.getTransaction().cancel();
              } catch (Throwable e2) {
                uncaughtException(e2);
              }

              transactionException(event, e);
            }
          }
        } catch (Throwable e) {
          try {
            uncaughtException(e);
          } catch (Throwable e2) {
            // If another error is thrown while trying to log the
            // first error, ignore it. This ensures that the
            // exitThread method is called, even if
            // OutOfMemoryErrors are being thrown around.
          }
        } finally {
          if (exitThread(forceExit)) {
            break;
          }
        }
      }
    }