static void
close_database(void)
{
  int i;
  int rc;

  if (!db) {
    return;
  }

  for (i = 0; i < 300; i++) {
    rc = sqlite3_close(db);

    if (rc == SQLITE_BUSY) {
      usleep(SLEEP_UTIME_FOR_BUSY);
      continue;
    }

    break;
  }

  if (IS_SQL_ERROR(rc)) {
    printf("%s(%d)\n", sqlite3_errmsg(db), sqlite3_errcode(db));
  }

  //printf("database is closed.\n");
}
bool
device_set_symbol_address(device_symbol_t symbol, unsigned long int address)
{
  device_id_t device_id;
  unsigned long int old;
  sqlite3_stmt *st;
  int rc;

  if (address == 0) {
    return false;
  }

  old = device_get_symbol_address(symbol);
  if (old == address) {
    return true;
  }

  if (old) {
    printf("Duplicate symbol \"%s\": old = 0x%08x, new = 0x%08x\n", symbol, old, address);
    return false;
  }

  device_id = get_device_id(true);

  rc = sqlite3_prepare(db, SQL_REGISTER_DEVICE_ADDRESS, -1, &st, NULL);

  if (!IS_SQL_ERROR(rc)) {
    rc = sqlite3_reset(st);
  }

  if (!IS_SQL_ERROR(rc)) {
    rc = sqlite3_bind_int(st, 1, device_id);
  }

  if (!IS_SQL_ERROR(rc)) {
    rc = sqlite3_bind_text(st, 2, symbol, -1, SQLITE_STATIC);
  }

  if (!IS_SQL_ERROR(rc)) {
    char hex_address[20] = { 0 };
    int length = snprintf(hex_address, sizeof(hex_address), "0x%08lx", address);
    rc = sqlite3_bind_text(st, 3, hex_address, length, SQLITE_STATIC);
  }

  if (!IS_SQL_ERROR(rc)) {
    rc = execute_sql(st);
  }

  if (IS_SQL_ERROR(rc)) {
    printf("%s(%d)\n", sqlite3_errmsg(db), sqlite3_errcode(db));
    sqlite3_finalize(st);

    return false;
  }

  sqlite3_finalize(st);

  return true;
}
void
print_reason_device_not_supported(void)
{
  char device[PROP_VALUE_MAX];
  char build_id[PROP_VALUE_MAX];
  const char *check_name;
  sqlite3_stmt *st;
  int rc;
  int i;

  if (!init_database()) {
    return;
  }

  __system_property_get("ro.product.model", device);
  __system_property_get("ro.build.display.id", build_id);

  check_name = NULL;

  rc = sqlite3_prepare(db, SQL_QUERY_DEVICE, -1, &st, NULL);

  if (!IS_SQL_ERROR(rc)) {
    rc = sqlite3_reset(st);
  }

  if (!IS_SQL_ERROR(rc)) {
    rc = sqlite3_bind_text(st, 1, device, -1, SQLITE_STATIC);
  }

  if (!IS_SQL_ERROR(rc)) {
    rc = sqlite3_bind_text(st, 2, build_id, -1, SQLITE_STATIC);
  }

  if (!IS_SQL_ERROR(rc)) {
    rc = execute_sql(st);
  }

  if (!IS_SQL_ERROR(rc)) {
    check_name = sqlite3_column_text(st, 1);
  }

  if (IS_SQL_ERROR(rc)) {
    printf("%s(%d)\n", sqlite3_errmsg(db), sqlite3_errcode(db));
  }

  if (check_name) {
    char check_property_value[PROP_VALUE_MAX];

    __system_property_get(check_name, check_property_value);

    printf("%s (%s %s) is not supported.\n", device, build_id, check_property_value);
  }
  else {
    printf("%s (%s) is not supported.\n", device, build_id);
  }

  sqlite3_finalize(st);
}
unsigned long int
device_get_symbol_address(device_symbol_t symbol)
{
  device_id_t device_id;
  sqlite3_stmt *st;
  int rc;
  unsigned long int value;

  device_id = detect_device();
  if (device_id == DEVICE_NOT_SUPPORTED) {
    return 0;
  }

  value = 0;

  rc = sqlite3_prepare(db, SQL_QUERY_DEVICE_ADDRESS, -1, &st, NULL);

  if (!IS_SQL_ERROR(rc)) {
    rc = sqlite3_reset(st);
  }

  if (!IS_SQL_ERROR(rc)) {
    rc = sqlite3_bind_int(st, 1, device_id);
  }

  if (!IS_SQL_ERROR(rc)) {
    rc = sqlite3_bind_text(st, 2, symbol, -1, SQLITE_STATIC);
  }

  if (!IS_SQL_ERROR(rc)) {
    rc = execute_sql(st);
  }

  if (!IS_SQL_ERROR(rc)) {
    sqlite3_value *value_object;
    int value_type;
    value_object = sqlite3_column_value(st, 0);
    value_type = sqlite3_value_type(value_object);
    if (value_type == SQLITE_INTEGER) {
      value = sqlite3_value_int(value_object);
    } else {
      const unsigned char *value_text;
      value_text = sqlite3_value_text(value_object);
      if (value_text) {
        sscanf(value_text, "%lx", &value);
      }
    }
  }

  if (IS_SQL_ERROR(rc)) {
    printf("%s(%d)\n", sqlite3_errmsg(db), sqlite3_errcode(db));
  }

  sqlite3_finalize(st);

  return value;
}
unsigned long int
device_get_symbol_address(device_symbol_t symbol)
{
  device_id_t device_id;
  sqlite3_stmt *st;
  int rc;
  unsigned long int value;

  device_id = detect_device();
  if (device_id == DEVICE_NOT_SUPPORTED) {
    return 0;
  }

  value = 0;

  rc = sqlite3_prepare(db, SQL_QUERY_DEVICE_ADDRESS, -1, &st, NULL);

  if (!IS_SQL_ERROR(rc)) {
    rc = sqlite3_reset(st);
  }

  if (!IS_SQL_ERROR(rc)) {
    rc = sqlite3_bind_int(st, 1, device_id);
  }

  if (!IS_SQL_ERROR(rc)) {
    rc = sqlite3_bind_text(st, 2, symbol, -1, SQLITE_STATIC);
  }

  if (!IS_SQL_ERROR(rc)) {
    rc = execute_sql(st);
  }

  if (!IS_SQL_ERROR(rc)) {
    value = sqlite3_column_int(st, 0);
  }

  if (IS_SQL_ERROR(rc)) {
    printf("%s(%d)\n", sqlite3_errmsg(db), sqlite3_errcode(db));
  }

  sqlite3_finalize(st);

  return value;
}
static device_id_t
get_device_id(bool do_regist)
{
  char device[PROP_VALUE_MAX];
  char build_id[PROP_VALUE_MAX];
  device_id_t device_id;
  const char *check_name;
  char name_buf[PROP_NAME_MAX];
  sqlite3_stmt *st;
  int rc;
  int i;

  if (!init_database()) {
    return DEVICE_NOT_SUPPORTED;
  }

  __system_property_get("ro.product.model", device);
  __system_property_get("ro.build.display.id", build_id);

  device_id = DEVICE_NOT_SUPPORTED;
  check_name = NULL;

  rc = sqlite3_prepare(db, SQL_QUERY_DEVICE, -1, &st, NULL);

  if (!IS_SQL_ERROR(rc)) {
    rc = sqlite3_reset(st);
  }

  if (!IS_SQL_ERROR(rc)) {
    rc = sqlite3_bind_text(st, 1, device, -1, SQLITE_STATIC);
  }

  if (!IS_SQL_ERROR(rc)) {
    rc = sqlite3_bind_text(st, 2, build_id, -1, SQLITE_STATIC);
  }

  if (!IS_SQL_ERROR(rc)) {
    for (rc = execute_sql(st); rc == SQLITE_ROW; rc = execute_sql(st)) {
      const char *check_value;

      device_id = sqlite3_column_int(st, 0);
      check_name = sqlite3_column_text(st, 1);
      check_value = sqlite3_column_text(st, 2);

      if (!check_name && !check_value) {
        break;
      }

      if (check_name && check_value) {
        char property_value[PROP_VALUE_MAX];

        __system_property_get(check_name, property_value);

        if (strcmp(property_value, check_value) == 0) {
          break;
        }

        strncpy(name_buf, check_name, sizeof (name_buf) - 1);
        name_buf[sizeof (name_buf) - 1] = '\0';

        check_name = name_buf;
      }

      device_id = DEVICE_NOT_SUPPORTED;
    }
  }

  if (IS_SQL_ERROR(rc)) {
    printf("%s(%d)\n", sqlite3_errmsg(db), sqlite3_errcode(db));

    sqlite3_finalize(st);

    return device_id;
  }

  sqlite3_finalize(st);

  if (!do_regist || device_id != DEVICE_NOT_SUPPORTED) {
    return device_id;
  }

  return register_device_id(check_name);
}
static device_id_t
register_device_id(const char *property_name)
{
  char device[PROP_VALUE_MAX];
  char build_id[PROP_VALUE_MAX];
  char buf[PROP_VALUE_MAX];
  const char *property_value;
  sqlite3_stmt *st;
  int rc;

  device_id_t device_id;

  if (!init_database()) {
    return DEVICE_NOT_SUPPORTED;
  }

  __system_property_get("ro.product.model", device);
  __system_property_get("ro.build.display.id", build_id);

  device_id = DEVICE_NOT_SUPPORTED;
  property_value = NULL;

  if (property_name) {
    __system_property_get(property_name, buf);
    property_value = buf;
  }

  rc = sqlite3_prepare(db, SQL_QUERY_LAST_DEVICE_ID, -1, &st, NULL);

  if (!IS_SQL_ERROR(rc)) {
    rc = sqlite3_reset(st);
  }

  if (!IS_SQL_ERROR(rc)) {
    for (rc = execute_sql(st); rc == SQLITE_ROW; rc = execute_sql(st)) {
      device_id = sqlite3_column_int(st, 0) + 1;
      if (device_id <= DEVICE_ID_REGISTER_START) {
        device_id = DEVICE_ID_REGISTER_START;
      }

      break;
    }
  }

  if (IS_SQL_ERROR(rc)) {
    printf("%s(%d)\n", sqlite3_errmsg(db), sqlite3_errcode(db));
    sqlite3_finalize(st);

    return DEVICE_NOT_SUPPORTED;
  }

  sqlite3_finalize(st);

  rc = sqlite3_prepare(db, SQL_REGISTER_DEVICE, -1, &st, NULL);

  if (!IS_SQL_ERROR(rc)) {
    rc = sqlite3_reset(st);
  }

  if (!IS_SQL_ERROR(rc)) {
    rc = sqlite3_bind_int(st, 1, device_id);
  }

  if (!IS_SQL_ERROR(rc)) {
    rc = sqlite3_bind_text(st, 2, device, -1, SQLITE_STATIC);
  }

  if (!IS_SQL_ERROR(rc)) {
    rc = sqlite3_bind_text(st, 3, build_id, -1, SQLITE_STATIC);
  }

  if (!IS_SQL_ERROR(rc)) {
    rc = sqlite3_bind_text(st, 4, property_name, -1, SQLITE_STATIC);
  }

  if (!IS_SQL_ERROR(rc)) {
    rc = sqlite3_bind_text(st, 5, property_value, -1, SQLITE_STATIC);
  }

  if (!IS_SQL_ERROR(rc)) {
    rc = execute_sql(st);
  }

  if (IS_SQL_ERROR(rc)) {
    printf("%s(%d)\n", sqlite3_errmsg(db), sqlite3_errcode(db));
    sqlite3_finalize(st);

    return DEVICE_NOT_SUPPORTED;
  }

  sqlite3_finalize(st);

  return device_id;
}