@Override
    protected Boolean doInBackground(Void... params) {
      final CountDownLatch countDownLatch = new CountDownLatch(1);

      StatFs stat = new StatFs(Environment.getDataDirectory().getAbsolutePath());

      try {
        if (canCleanInternalCache(CleanerService.this)) {
          mFreeStorageAndNotifyMethod.invoke(
              getPackageManager(),
              (long) stat.getBlockCount() * (long) stat.getBlockSize(),
              new IPackageDataObserver.Stub() {
                @Override
                public void onRemoveCompleted(String packageName, boolean succeeded)
                    throws RemoteException {
                  countDownLatch.countDown();
                }
              });
        } else {
          countDownLatch.countDown();
        }

        if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
          if (isExternalStorageWritable()) {
            final File externalDataDirectory =
                new File(
                    Environment.getExternalStorageDirectory().getAbsolutePath() + "/Android/data");

            final String externalCachePath = externalDataDirectory.getAbsolutePath() + "/%s/cache";

            final File[] files = externalDataDirectory.listFiles();

            for (File file : files) {
              if (!deleteDirectory(
                  new File(String.format(externalCachePath, file.getName())), true)) {
                Log.e(TAG, "External storage suddenly becomes unavailable");

                return false;
              }
            }
          } else {
            Log.d(TAG, "External storage is unavailable");
          }
        }

        countDownLatch.await();
      } catch (InterruptedException | IllegalAccessException e) {
        e.printStackTrace();
      } catch (InvocationTargetException e) {
        return false;
      }

      return true;
    }