diff options
author | Eugene Kudelevsky <Eugene.Kudelevsky@jetbrains.com> | 2013-10-07 10:36:56 +0400 |
---|---|---|
committer | Tor Norbye <tnorbye@google.com> | 2013-10-10 10:07:24 -0700 |
commit | 5ec60f348b1b73004e9c62fc88592a6afd659833 (patch) | |
tree | 0e4c58b04d1403a01723a8c0c6dfab37c9ed97e3 /android/ultimate | |
parent | c694bba2a8637a147dd9dff8b833a8be816f7baf (diff) | |
download | idea-5ec60f348b1b73004e9c62fc88592a6afd659833.tar.gz |
install command line tool onto device to get exact modification time; use it instead of ls and md5 computation, since md5 may be not available on some devices
Diffstat (limited to 'android/ultimate')
-rw-r--r-- | android/ultimate/get_modification_time/jni/Android.mk | 22 | ||||
-rw-r--r-- | android/ultimate/get_modification_time/jni/Application.mk | 1 | ||||
-rw-r--r-- | android/ultimate/get_modification_time/jni/get_modification_time.c | 15 | ||||
-rwxr-xr-x | android/ultimate/src/native_tools/armeabi-v7a/get_modification_time | bin | 0 -> 9500 bytes | |||
-rwxr-xr-x | android/ultimate/src/native_tools/armeabi/get_modification_time | bin | 0 -> 9496 bytes | |||
-rwxr-xr-x | android/ultimate/src/native_tools/mips/get_modification_time | bin | 0 -> 5356 bytes | |||
-rwxr-xr-x | android/ultimate/src/native_tools/x86/get_modification_time | bin | 0 -> 5276 bytes | |||
-rw-r--r-- | android/ultimate/src/org/jetbrains/android/database/AndroidDbUtil.java | 197 | ||||
-rw-r--r-- | android/ultimate/src/org/jetbrains/android/database/AndroidRemoteDataBaseManager.java | 3 | ||||
-rw-r--r-- | android/ultimate/src/org/jetbrains/android/database/AndroidSynchronizeHandler.java | 13 | ||||
-rw-r--r-- | android/ultimate/src/org/jetbrains/android/database/AndroidUploadDatabaseAction.java | 7 |
11 files changed, 186 insertions, 72 deletions
diff --git a/android/ultimate/get_modification_time/jni/Android.mk b/android/ultimate/get_modification_time/jni/Android.mk new file mode 100644 index 00000000000..f9092b41024 --- /dev/null +++ b/android/ultimate/get_modification_time/jni/Android.mk @@ -0,0 +1,22 @@ +# Copyright (C) 2009 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. +# +LOCAL_PATH := $(call my-dir) + +include $(CLEAR_VARS) + +LOCAL_MODULE := get_modification_time +LOCAL_SRC_FILES := get_modification_time.c + +include $(BUILD_EXECUTABLE) diff --git a/android/ultimate/get_modification_time/jni/Application.mk b/android/ultimate/get_modification_time/jni/Application.mk new file mode 100644 index 00000000000..a252a72d729 --- /dev/null +++ b/android/ultimate/get_modification_time/jni/Application.mk @@ -0,0 +1 @@ +APP_ABI := all diff --git a/android/ultimate/get_modification_time/jni/get_modification_time.c b/android/ultimate/get_modification_time/jni/get_modification_time.c new file mode 100644 index 00000000000..0ccd2705029 --- /dev/null +++ b/android/ultimate/get_modification_time/jni/get_modification_time.c @@ -0,0 +1,15 @@ +#include <sys/stat.h> +#include <stdio.h> + +int main(int argc, char** args) { + struct stat st; + char* filename = args[1]; + + if (stat(filename, &st) < 0) { + perror(filename); + return 1; + } + printf("%lu\n", st.st_mtime); + return 0; +} + diff --git a/android/ultimate/src/native_tools/armeabi-v7a/get_modification_time b/android/ultimate/src/native_tools/armeabi-v7a/get_modification_time Binary files differnew file mode 100755 index 00000000000..022854b551d --- /dev/null +++ b/android/ultimate/src/native_tools/armeabi-v7a/get_modification_time diff --git a/android/ultimate/src/native_tools/armeabi/get_modification_time b/android/ultimate/src/native_tools/armeabi/get_modification_time Binary files differnew file mode 100755 index 00000000000..1e68fd5ac4b --- /dev/null +++ b/android/ultimate/src/native_tools/armeabi/get_modification_time diff --git a/android/ultimate/src/native_tools/mips/get_modification_time b/android/ultimate/src/native_tools/mips/get_modification_time Binary files differnew file mode 100755 index 00000000000..ae60c2ade1c --- /dev/null +++ b/android/ultimate/src/native_tools/mips/get_modification_time diff --git a/android/ultimate/src/native_tools/x86/get_modification_time b/android/ultimate/src/native_tools/x86/get_modification_time Binary files differnew file mode 100755 index 00000000000..f481f260985 --- /dev/null +++ b/android/ultimate/src/native_tools/x86/get_modification_time diff --git a/android/ultimate/src/org/jetbrains/android/database/AndroidDbUtil.java b/android/ultimate/src/org/jetbrains/android/database/AndroidDbUtil.java index 29636cee73b..7552969ee02 100644 --- a/android/ultimate/src/org/jetbrains/android/database/AndroidDbUtil.java +++ b/android/ultimate/src/org/jetbrains/android/database/AndroidDbUtil.java @@ -1,9 +1,6 @@ package org.jetbrains.android.database; -import com.android.ddmlib.AndroidDebugBridge; -import com.android.ddmlib.IDevice; -import com.android.ddmlib.MultiLineReceiver; -import com.android.ddmlib.SyncService; +import com.android.ddmlib.*; import com.intellij.javaee.dataSource.LoaderContext; import com.intellij.javaee.module.view.dataSource.DataSourceUiUtil; import com.intellij.javaee.module.view.dataSource.LocalDataSource; @@ -12,16 +9,17 @@ import com.intellij.openapi.application.ApplicationNamesInfo; import com.intellij.openapi.diagnostic.Logger; import com.intellij.openapi.progress.ProgressIndicator; import com.intellij.openapi.project.Project; +import com.intellij.openapi.util.io.FileUtil; import com.intellij.persistence.database.autoconfig.DataSourceConfigUtil; import com.intellij.persistence.database.autoconfig.MissingDriversNotification; +import com.intellij.util.io.URLUtil; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.io.File; +import java.io.*; +import java.net.URL; import java.util.Collections; import java.util.concurrent.TimeUnit; -import java.util.regex.Matcher; -import java.util.regex.Pattern; /** * @author Eugene.Kudelevsky @@ -31,11 +29,10 @@ class AndroidDbUtil { public static final Object DB_SYNC_LOCK = new Object(); public static final String TEMP_REMOTE_DB_PATH = "/data/local/tmp/intellij_temp_db_file"; + public static final String TEMP_REMOTE_GET_MODIFICATION_TIME_TOOL_PATH = + "/data/local/tmp/intellij_native_tools/get_modification_time"; public static final long DB_COPYING_TIMEOUT_SEC = 30; public static final int SHELL_COMMAND_TIMEOUT_SECONDS = 2; - private static final Pattern LS_L_OUTPUT_PATTERN = Pattern.compile( - "^([bcdlsp-][-r][-w][-xsS][-r][-w][-xsS][-r][-w][-xstST])\\s+(\\S+)\\s+(\\S+)\\s+" + - "([\\d\\s,]*)\\s+(\\d{4}-\\d\\d-\\d\\d)\\s+(\\d\\d:\\d\\d)\\s+(.*)$"); private AndroidDbUtil() { } @@ -175,44 +172,150 @@ class AndroidDbUtil { return null; } - @Nullable - public static String getRemoteDbModificationTimeAndSize(@NotNull IDevice device, - @NotNull final String packageName, - @NotNull String dbName, - @NotNull AndroidDbErrorReporter errorReporter) { - final String command = "run-as " + packageName + " ls -l /data/data/" + packageName + "/databases/" + dbName; - final String result = executeSingleCommand(device, errorReporter, command); - return result != null ? parseModificationTimeAndSizeFromLsResult(result, errorReporter) : null; + + private static boolean installGetModificationTimeTool(@NotNull IDevice device, + @NotNull AndroidDbErrorReporter reporter, + @NotNull ProgressIndicator progressIndicator) { + String abi = device.getProperty("ro.product.cpu.abi"); + + if (abi == null) { + abi = "armeabi"; + } + final String urlStr = "/native_tools/" + abi + "/get_modification_time"; + final URL url = AndroidDbUtil.class.getResource(urlStr); + + if (url == null) { + LOG.error("Cannot find resource " + urlStr); + return false; + } + final String remoteToolPath = TEMP_REMOTE_GET_MODIFICATION_TIME_TOOL_PATH; + + if (!pushGetModificationTimeTool(device, url, reporter, progressIndicator, remoteToolPath)) { + return false; + } + final String chmodResult = executeSingleCommand(device, reporter, "chmod 755 " + remoteToolPath); + + if (chmodResult == null) { + return false; + } + if (!chmodResult.isEmpty()) { + reporter.reportError(chmodResult); + return false; + } + return true; + } + + private static boolean pushGetModificationTimeTool(@NotNull IDevice device, + @NotNull URL url, + @NotNull AndroidDbErrorReporter reporter, + @NotNull ProgressIndicator progressIndicator, + @NotNull String remotePath) { + final File toolLocalCopy; + + try { + toolLocalCopy = FileUtil.createTempFile("android_get_modification_time_tool", "tmp"); + } + catch (IOException e) { + reporter.reportError(e); + return false; + } + try { + if (!copyResourceToFile(url, toolLocalCopy, reporter)) { + return false; + } + + try { + final SyncService service = device.getSyncService(); + try { + service.pushFile(toolLocalCopy.getPath(), remotePath, + new MySyncProgressMonitor(progressIndicator)); + } + finally { + service.close(); + } + } + catch (Exception e) { + reporter.reportError(e); + return false; + } + } + finally { + FileUtil.delete(toolLocalCopy); + } + return true; + } + + private static boolean copyResourceToFile(@NotNull URL url, @NotNull File file, @NotNull AndroidDbErrorReporter reporter) { + try { + final InputStream is = new BufferedInputStream(URLUtil.openStream(url)); + final OutputStream os = new BufferedOutputStream(new FileOutputStream(file)); + + try { + FileUtil.copy(is, os); + } + finally { + is.close(); + os.close(); + } + } + catch (IOException e) { + reporter.reportError(e); + return false; + } + return true; } @Nullable - static String getRemoteDbMd5Hash(@NotNull IDevice device, - @NotNull final String packageName, - @NotNull String dbName, - @NotNull AndroidDbErrorReporter errorReporter) { - final String command = "run-as " + packageName + " md5 /data/data/" + packageName + "/databases/" + dbName; - final String result = executeSingleCommand(device, errorReporter, command); - - if (result == null) { + public static Long getModificationTime(@NotNull IDevice device, + @NotNull final String packageName, + @NotNull String dbName, + @NotNull AndroidDbErrorReporter errorReporter, + @NotNull ProgressIndicator progressIndicator) { + final String path = TEMP_REMOTE_GET_MODIFICATION_TIME_TOOL_PATH; + final String lsResult = executeSingleCommand(device, errorReporter, "ls " + path); + + if (lsResult == null) { return null; } - if (result.startsWith("run-as:")) { - errorReporter.reportError(result); - return null; + boolean reinstalled = false; + + if (!lsResult.equals(path)) { + if (!installGetModificationTimeTool(device, errorReporter, progressIndicator)) { + return null; + } + reinstalled = true; } - final int idx = result.indexOf(' '); + Long l = doGetModificationTime(device, packageName, dbName, errorReporter); - if (idx < 0) { - errorReporter.reportError(result); - return null; + if (l != null) { + return l; + } + if (!reinstalled) { + // get_modification_time tools seems to be broken, so reinstall it for future + installGetModificationTimeTool(device, errorReporter, progressIndicator); } - final String md5Str = result.substring(0, idx); + return null; + } - if (md5Str.length() != 32) { - errorReporter.reportError(result); + @Nullable + private static Long doGetModificationTime(@NotNull IDevice device, + @NotNull String packageName, + @NotNull String dbName, + @NotNull AndroidDbErrorReporter errorReporter) { + final String command = "run-as " + packageName + " " + TEMP_REMOTE_GET_MODIFICATION_TIME_TOOL_PATH + + " /data/data/" + packageName + "/databases/" + dbName; + final String s = executeSingleCommand(device, errorReporter, command); + + if (s == null) { + return null; + } + try { + return Long.parseLong(s); + } + catch (NumberFormatException e) { + errorReporter.reportError(s); return null; } - return md5Str; } @Nullable @@ -231,26 +334,6 @@ class AndroidDbUtil { return receiver.getOutput(); } - @Nullable - private static String parseModificationTimeAndSizeFromLsResult(@NotNull String s, @NotNull AndroidDbErrorReporter errorReporter) { - final Matcher matcher = LS_L_OUTPUT_PATTERN.matcher(s); - - if (!matcher.matches()) { - errorReporter.reportError(s); - return null; - } - final String sizeStr = matcher.group(4); - final String dateStr = matcher.group(5); - final String timeStr = matcher.group(6); - final String fullDateStr = dateStr + "|" + timeStr + "|" + sizeStr; - - if (sizeStr.length() == 0 || dateStr.length() == 0 || timeStr.length() == 0) { - LOG.error("Incorrect ls output: " + fullDateStr); - return null; - } - return fullDateStr; - } - public static void detectDriverAndRefresh(@NotNull Project project, @NotNull AndroidDataSource dataSource, boolean create) { if (!DataSourceConfigUtil.detectDriverClassPath(project, dataSource.getDriverClass(), dataSource.getClasspathElements())) { final String message = diff --git a/android/ultimate/src/org/jetbrains/android/database/AndroidRemoteDataBaseManager.java b/android/ultimate/src/org/jetbrains/android/database/AndroidRemoteDataBaseManager.java index 8838000ce91..4ec8c9d7913 100644 --- a/android/ultimate/src/org/jetbrains/android/database/AndroidRemoteDataBaseManager.java +++ b/android/ultimate/src/org/jetbrains/android/database/AndroidRemoteDataBaseManager.java @@ -173,8 +173,7 @@ public class AndroidRemoteDataBaseManager implements PersistentStateComponent<An @Tag("db-info") public static class MyDatabaseInfo { - public String lsResult = ""; - public String md5Hash = ""; + public long modificationTime = 0; public Set<String> referringProjects = new HashSet<String>(); } } diff --git a/android/ultimate/src/org/jetbrains/android/database/AndroidSynchronizeHandler.java b/android/ultimate/src/org/jetbrains/android/database/AndroidSynchronizeHandler.java index dbfea8c1b1b..13d4f9ce331 100644 --- a/android/ultimate/src/org/jetbrains/android/database/AndroidSynchronizeHandler.java +++ b/android/ultimate/src/org/jetbrains/android/database/AndroidSynchronizeHandler.java @@ -82,10 +82,10 @@ public class AndroidSynchronizeHandler extends SynchronizeHandler { final String packageName = dbConnectionInfo.getPackageName(); final String dbName = dbConnectionInfo.getDbName(); - final String lsResult = AndroidDbUtil.getRemoteDbModificationTimeAndSize(device, packageName, dbName, errorReporter); + final Long modificationTime = AndroidDbUtil.getModificationTime(device, packageName, dbName, errorReporter, progressIndicator); progressIndicator.checkCanceled(); - if (lsResult == null) { + if (modificationTime == null) { return; } final AndroidRemoteDataBaseManager remoteDbManager = AndroidRemoteDataBaseManager.getInstance(); @@ -94,19 +94,14 @@ public class AndroidSynchronizeHandler extends SynchronizeHandler { if (info == null) { info = new AndroidRemoteDataBaseManager.MyDatabaseInfo(); } - final String remoteDbMd5 = AndroidDbUtil.getRemoteDbMd5Hash(device, packageName, dbName, errorReporter); progressIndicator.checkCanceled(); - if (remoteDbMd5 == null) { - return; - } final File localDbFile = new File(dataSource.buildLocalDbFileOsPath()); info.referringProjects.add(FileUtil.toCanonicalPath(project.getBasePath())); - if (!localDbFile.exists() || !lsResult.equals(info.lsResult) || !remoteDbMd5.equals(info.md5Hash)) { + if (!localDbFile.exists() || !modificationTime.equals(info.modificationTime)) { if (AndroidDbUtil.downloadDatabase(device, packageName, dbName, localDbFile, progressIndicator, errorReporter)) { - info.lsResult = lsResult; - info.md5Hash = remoteDbMd5; + info.modificationTime = modificationTime; remoteDbManager.setDatabaseInfo(deviceSerialNumber, packageName, dbName, info); } } diff --git a/android/ultimate/src/org/jetbrains/android/database/AndroidUploadDatabaseAction.java b/android/ultimate/src/org/jetbrains/android/database/AndroidUploadDatabaseAction.java index f8c893aeda6..a6902d2c6ab 100644 --- a/android/ultimate/src/org/jetbrains/android/database/AndroidUploadDatabaseAction.java +++ b/android/ultimate/src/org/jetbrains/android/database/AndroidUploadDatabaseAction.java @@ -105,9 +105,9 @@ public class AndroidUploadDatabaseAction extends AnAction { return; } if (AndroidDbUtil.uploadDatabase(device, packageName, dbName, localDbFilePath, indicator, errorReporter)) { - final String lsResult = AndroidDbUtil.getRemoteDbModificationTimeAndSize(device, packageName, dbName, errorReporter); + final Long modificationTime = AndroidDbUtil.getModificationTime(device, packageName, dbName, errorReporter, indicator); - if (lsResult != null) { + if (modificationTime != null) { final String deviceSerialNumber = device.getSerialNumber(); AndroidRemoteDataBaseManager.MyDatabaseInfo dbInfo = AndroidRemoteDataBaseManager. getInstance().getDatabaseInfo(deviceSerialNumber, packageName, dbName); @@ -115,8 +115,7 @@ public class AndroidUploadDatabaseAction extends AnAction { if (dbInfo == null) { dbInfo = new AndroidRemoteDataBaseManager.MyDatabaseInfo(); } - dbInfo.lsResult = lsResult; - dbInfo.md5Hash = localFileMd5Hash; + dbInfo.modificationTime = modificationTime; AndroidRemoteDataBaseManager.getInstance().setDatabaseInfo(deviceSerialNumber, packageName, dbName, dbInfo); } } |