commit badb89008b8a5537fb8213d79f830c636320bb7b Author: virjar Date: Thu Aug 26 16:26:06 2021 +0800 init diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..05a9d87 --- /dev/null +++ b/.gitignore @@ -0,0 +1,44 @@ +*.iml +.gradle +/local.properties +/.idea/workspace.xml +/.idea/libraries +.DS_Store +/build +/captures +.externalNativeBuild + +# kdiff3 ignore +*.orig + +# maven ignore +target/ + +# eclipse ignore +.settings/ +.project +.classpath + +# idea ignore +.idea/ +*.ipr +*.iml +*.iws + +# temp ignore +*.log +*.cache +*.diff +*.patch +*.tmp + +# system ignore +.DS_Store +Thumbs.db + + +*.apk +.cxx/ +build/ + +app/src/main/assets/config.properties \ No newline at end of file diff --git a/README.md b/README.md new file mode 100755 index 0000000..a25df3b --- /dev/null +++ b/README.md @@ -0,0 +1,25 @@ +# SSHDroid + +给android app提供的一个sshd服务,起主要作用是提供一个交互式的shell工具, +我们可以通过他访问app的内部数据文件。 + +**请注意本服务和android原生adb是不冲突的,因为adb无法访问app私有文件目录,SSHDroid则通过插件注入的方式将私有文件系统暴露出来** + + +## 运行 + +1. 复制文件: ``app/src/main/assets/config.template.properties``-> `` app/src/main/assets/config.properties`` +2. 修改内容 + - targetPackage: 需要被注入的进程 + - ssdServerPort: 启动的端口号,请注意不要和其他服务冲突 + - newProcess: 是否需要在新进程中启动,如果你的app开启了分身,那么最好将这个配置设置为true。因为分身功能将会破坏原有文件系统(特别是平头哥系统) +3. 安装并运行插件 +4. 在电脑上面运行adb forward,如: ``adb forward tcp:3478 tcp:3478`` +5. 使用电脑连接服务,如: + - ssh 127.0.0.1 -p 3478 登陆shell + - scp -P 3478 ./test.txt 127.0.0.1:/data/data/xxx/files/ + - scp -P 3478 127.0.0.1:/data/data/xxx/files/aaa.log ~/Desktop/ + +## 自动化和集群化 +请基于当前工具做二次封装 + diff --git a/android.jks b/android.jks new file mode 100644 index 0000000..0f722f7 Binary files /dev/null and b/android.jks differ diff --git a/app/build.gradle b/app/build.gradle new file mode 100755 index 0000000..7dcc801 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,57 @@ +apply plugin: 'com.android.application' + +android { + signingConfigs { + config { + storeFile file('../android.jks') + storePassword 'android' + keyAlias = 'android' + keyPassword 'android' + } + } + compileOptions { + sourceCompatibility 1.8 + targetCompatibility 1.8 + } + compileSdkVersion 27 + buildToolsVersion '28.0.3' + defaultConfig { + applicationId "com.virjar.sshdroid" + minSdkVersion 24 + targetSdkVersion 27 + versionCode 3 + versionName "1.3" + + + signingConfig signingConfigs.config + } + + buildTypes { + release { + minifyEnabled false + shrinkResources false + proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' + } + } + + + packagingOptions { + exclude 'META-INF/DEPENDENCIES' + } + +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + compileOnly 'com.virjar:ratel-api:1.3.6' + implementation 'com.android.support:appcompat-v7:27.1.1' + implementation "com.android.support:support-v4:27.1.1" + implementation "com.android.support:support-annotations:28.0.0" + implementation 'org.slf4j:slf4j-api:1.7.31' + implementation('org.apache.sshd:sshd-core:2.7.0') + implementation('org.apache.sshd:sshd-scp:2.7.0') + implementation('org.apache.sshd:sshd-sftp:2.7.0') + implementation 'org.bouncycastle:bcpkix-jdk15on:1.69' + + +} diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100755 index 0000000..d230c71 --- /dev/null +++ b/app/proguard-rules.pro @@ -0,0 +1,33 @@ +# Add project specific ProGuard rules here. +# By default, the flags in this file are appended to flags specified +# in C:\Users\Bin\AppData\Local\Android\sdk/tools/proguard/proguard-android.txt +# You can edit the include path and order by changing the proguardFiles +# directive in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# Add any project specific keep options here: + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + + +-dontwarn org.bouncycastle.** +-dontpreverify +-dontobfuscate +-ignorewarnings + +-keep class org.bouncycastle.openssl.** +-keep class org.bouncycastle.jce.provider.BouncyCastleProvider{*;} + + +-keep class com.virjar.sshdroid.Main{*;} +-keep class com.virjar.sshdroid.SSHD{*;} + + +-keepattributes Exceptions,InnerClasses,Signature,Deprecated,SourceFile,LineNumberTable,LocalVariable*Table,*Annotation*,Synthetic,EnclosingMethod diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100755 index 0000000..34f3c3c --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,47 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/assets/config.template.properties b/app/src/main/assets/config.template.properties new file mode 100644 index 0000000..322dfc9 --- /dev/null +++ b/app/src/main/assets/config.template.properties @@ -0,0 +1,3 @@ +targetPackage=com.xxx.xxx +ssdServerPort=3478 +newProcess=false \ No newline at end of file diff --git a/app/src/main/assets/sshdroid.pem b/app/src/main/assets/sshdroid.pem new file mode 100644 index 0000000..3bab08a --- /dev/null +++ b/app/src/main/assets/sshdroid.pem @@ -0,0 +1,16 @@ +-----BEGIN EC PRIVATE KEY----- +MIIChwIBAQRCASavnPa0fS6R9cx97Y0PBy0dqwwHnG4zlf5h5UylgV/8QMvOcgWr +a3mT1cabJMYOrdVtzJjX3QAJATgIg4GtdAw/oIIBsDCCAawCAQEwTQYHKoZIzj0B +AQJCAf////////////////////////////////////////////////////////// +////////////////////////////MIGIBEIB//////////////////////////// +//////////////////////////////////////////////////////////wEQgBR +lT65YY4cmh+SmiGgtoVA7qLacluZsxXzuLSJkY7xCeFWGTlR7H6TexZSwL07sb8H +NXPfiD0sNPHvRR/Ua1A/AASBhQQAxoWOBrcEBOnNnj7LZiOVtEKcZIE5BT+1Ifgo +r2BrTT26oUted+/nWSj+HcEnov+o3jNIs8GFakKb+X5+McLlvWYBGDkpaniaO8AE +XIpftCx9G9mY9URJV5tEaBevvRcnPmYsl+5ymV70JkDFULkBP60HYTU8cIaicsJA +iL6Udp/RZlACQgH///////////////////////////////////////////pRhoeD +vy+Wa3/MAUj3CaXQO7XJuImcR667b7cekThkCQIBAaGBiQOBhgAEAV7oPlj9TSuF +PkCANSWOrGeKLM6tl0Kc5prjSyc1kerg069XmCiQfbpWV2PKe0ZYsIpt230h5ahK +jlYbWcLHd7v9Ael2wzo9tC63eZtYH8/WigjEhIEAVYL1EeIxNI7kx52dpe+Lu0zo +L2WmjqD84VnEGNKZeNw0Et8YqVu0I5aI/b9O +-----END EC PRIVATE KEY----- diff --git a/app/src/main/assets/xposed_init b/app/src/main/assets/xposed_init new file mode 100755 index 0000000..011aae3 --- /dev/null +++ b/app/src/main/assets/xposed_init @@ -0,0 +1 @@ +com.virjar.sshdroid.Main \ No newline at end of file diff --git a/app/src/main/ic_launcher-web.png b/app/src/main/ic_launcher-web.png new file mode 100755 index 0000000..d823eb9 Binary files /dev/null and b/app/src/main/ic_launcher-web.png differ diff --git a/app/src/main/java/com/virjar/sshdroid/Configs.java b/app/src/main/java/com/virjar/sshdroid/Configs.java new file mode 100644 index 0000000..bf5e529 --- /dev/null +++ b/app/src/main/java/com/virjar/sshdroid/Configs.java @@ -0,0 +1,41 @@ +package com.virjar.sshdroid; + +import android.util.Log; + +import java.io.IOException; +import java.io.InputStream; +import java.util.Properties; + +import static com.virjar.sshdroid.SSHD.TAG; + +public class Configs { + public static int ssdServerPort; + public static boolean newProcess; + public static String targetPackage; + public static Properties properties; + + static { + try { + load(); + } catch (IOException e) { + throw new RuntimeException("error", e); + } + } + + private static void load() throws IOException { + InputStream stream = SSHD.class.getClassLoader().getResourceAsStream("assets/config.properties"); + if (stream == null) { + Log.e(TAG, "can not find resource : assets/config.properties"); + return; + } + properties = new Properties(); + properties.load(stream); + + targetPackage = properties.getProperty("targetPackage"); + + + ssdServerPort = Integer.parseInt(properties.getProperty("ssdServerPort")); + newProcess = Boolean.parseBoolean(properties.getProperty("newProcess")); + } + +} diff --git a/app/src/main/java/com/virjar/sshdroid/Main.java b/app/src/main/java/com/virjar/sshdroid/Main.java new file mode 100755 index 0000000..6886cc5 --- /dev/null +++ b/app/src/main/java/com/virjar/sshdroid/Main.java @@ -0,0 +1,21 @@ +package com.virjar.sshdroid; + + +import android.util.Log; + +import com.virjar.ratel.api.rposed.IRposedHookLoadPackage; +import com.virjar.ratel.api.rposed.callbacks.RC_LoadPackage; + +public class Main implements IRposedHookLoadPackage { + + @Override + public void handleLoadPackage(final RC_LoadPackage.LoadPackageParam lpparam) throws Throwable { + try { + SSHD.startup(lpparam.processName, lpparam.modulePath); + } catch (Throwable throwable) { + Log.e(SSHD.TAG, "start SSHD error", throwable); + } + + } + +} diff --git a/app/src/main/java/com/virjar/sshdroid/MainActivity.java b/app/src/main/java/com/virjar/sshdroid/MainActivity.java new file mode 100644 index 0000000..ade0d94 --- /dev/null +++ b/app/src/main/java/com/virjar/sshdroid/MainActivity.java @@ -0,0 +1,26 @@ +package com.virjar.sshdroid; + +import android.os.Bundle; +import android.support.v7.app.AppCompatActivity; +import android.widget.TextView; + +public class MainActivity extends AppCompatActivity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_main); + + TextView textView = findViewById(R.id.id_newProcess); + textView.setText(Configs.newProcess ? " 是" : " 否"); + + + TextView textViewTargetApp = findViewById(R.id.id_targetApp); + textViewTargetApp.setText(Configs.targetPackage); + + + TextView textViewTargetPort = findViewById(R.id.id_targetPort); + textViewTargetPort.setText(String.valueOf(Configs.ssdServerPort)); + + } +} diff --git a/app/src/main/java/com/virjar/sshdroid/SSHD.java b/app/src/main/java/com/virjar/sshdroid/SSHD.java new file mode 100644 index 0000000..ffdb31e --- /dev/null +++ b/app/src/main/java/com/virjar/sshdroid/SSHD.java @@ -0,0 +1,152 @@ +package com.virjar.sshdroid; + +import android.os.Build; +import android.util.Log; + +import com.virjar.ratel.api.RatelToolKit; + +import org.apache.sshd.common.keyprovider.ClassLoadableResourceKeyPairProvider; +import org.apache.sshd.common.util.security.SecurityUtils; +import org.apache.sshd.common.util.security.bouncycastle.BouncyCastleKeyPairResourceParser; +import org.apache.sshd.scp.server.ScpCommandFactory; +import org.apache.sshd.server.SshServer; +import org.apache.sshd.server.auth.password.AcceptAllPasswordAuthenticator; +import org.apache.sshd.server.auth.pubkey.AcceptAllPublickeyAuthenticator; +import org.apache.sshd.server.forward.AcceptAllForwardingFilter; +import org.apache.sshd.server.shell.ProcessShellFactory; +import org.apache.sshd.sftp.server.SftpSubsystemFactory; +import org.bouncycastle.jce.provider.BouncyCastleProvider; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.OutputStream; +import java.security.Security; +import java.util.Collections; +import java.util.Locale; + +import external.org.apache.commons.io.IOUtils; + +public class SSHD { + public static final String TAG = "SSHDroid"; + + public static void startup(String nowProcessName, String modulePath) throws IOException { + + if (!nowProcessName.equals(Configs.targetPackage)) { + return; + } + + Log.i(TAG, "begin start SSHDroid service"); + + String mockUserHome = RatelToolKit.sContext.getFilesDir().getAbsolutePath(); + + if (!Configs.newProcess) { + startup(Configs.ssdServerPort, mockUserHome, false); + return; + } + + // 需要在新进程中启动 + String processName = String.format("SSHDroid:%s", nowProcessName); + String cmd = String.format(Locale.ENGLISH, CMD_FORMATTER, + modulePath, processName, Configs.ssdServerPort, mockUserHome); + Log.i(TAG, "cmd: " + cmd); + + + Process process = Runtime.getRuntime().exec("sh"); + OutputStream os = process.getOutputStream(); + os.write(cmd.getBytes()); + os.flush(); + os.close(); + + new StreamReadTask(process.getInputStream()).start(); + new StreamReadTask(process.getErrorStream()).start(); + } + + private static final String CMD_FORMATTER = + "(CLASSPATH=%s /system/bin/app_process /system/bin --nice-name=%s " + + SSHD.class.getName() + + " %d %s)&"; + + + public static void main(String[] args) { + int ssdServerPort = Integer.parseInt(args[0]); + String userHome = args[1]; + + Security.addProvider(new BouncyCastleProvider()); + startup(ssdServerPort, userHome, true); + } + + + private static void reinstallBCProvider() { + if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.O_MR1) { + // android8之前的不需要处理 + // https://stackoverflow.com/questions/55934898/how-to-run-an-apache-mina-sshd-server-2-2-0-on-android-pie/68251093#68251093 + return; + } + Security.removeProvider("BC"); + Security.addProvider(new BouncyCastleProvider()); + } + + public static void startup(int ssdServerPort, String userHome, boolean newProcess) { + Log.i(TAG, "prepare start SshServer with port: " + ssdServerPort + " mock userHome: " + userHome); + + reinstallBCProvider(); + + // android 下没有这个环境 + System.setProperty("user.home", userHome); + try { + SshServer sshd = SshServer.setUpDefaultServer(); + sshd.setPort(ssdServerPort); + sshd.setShellFactory(new ProcessShellFactory("bash", "sh")); + sshd.setCommandFactory(new ScpCommandFactory()); + sshd.setSubsystemFactories(Collections.singletonList(new SftpSubsystemFactory())); + SecurityUtils.setKeyPairResourceParser(BouncyCastleKeyPairResourceParser.INSTANCE); + sshd.setKeyPairProvider(new ClassLoadableResourceKeyPairProvider(SSHD.class.getClassLoader(), "assets/sshdroid.pem")); + sshd.setPasswordAuthenticator(AcceptAllPasswordAuthenticator.INSTANCE); + sshd.setPublickeyAuthenticator(AcceptAllPublickeyAuthenticator.INSTANCE); + sshd.setForwardingFilter(AcceptAllForwardingFilter.INSTANCE); + try { + sshd.start(); + Log.i(TAG, "server startup finished"); + if (newProcess) { + Thread.sleep(Integer.MAX_VALUE); + } + } catch (IOException e) { + Log.e(SSHD.class.getSimpleName(), "start ssd error", e); + } + } catch (Throwable throwable) { + Log.e(TAG, "startup error", throwable); + } finally { + System.setProperty("user.home", ""); + } + } + + + private static class StreamReadTask extends Thread { + private final InputStream inputStream; + + StreamReadTask(InputStream inputStream) { + this.inputStream = inputStream; + } + + + @Override + public void run() { + BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(inputStream)); + String line; + try { + + while ((line = bufferedReader.readLine()) != null) { + Log.i(SSHD.TAG, line); + } + } catch (IOException e) { + Log.e(SSHD.TAG, "error", e); + } finally { + IOUtils.closeQuietly(inputStream); + } + } + } + + +} diff --git a/app/src/main/java/org/slf4j/impl/AndroidLogger.java b/app/src/main/java/org/slf4j/impl/AndroidLogger.java new file mode 100755 index 0000000..299c787 --- /dev/null +++ b/app/src/main/java/org/slf4j/impl/AndroidLogger.java @@ -0,0 +1,245 @@ +/* + * Created 21.10.2009 + * + * Copyright (c) 2009-2012 SLF4J.ORG + * + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package org.slf4j.impl; + +import org.slf4j.Marker; +import org.slf4j.helpers.MarkerIgnoringBase; +import org.slf4j.helpers.MessageFormatter; + +import android.util.Log; + +import com.virjar.sshdroid.SSHD; + +/** + * A simple implementation that delegates all log requests to the Google Android + * logging facilities. Note that this logger does not support {@link Marker}. + * That is, methods taking marker data simply invoke the corresponding method + * without the Marker argument, discarding any marker data passed as argument. + *

+ * The logging levels specified for SLF4J can be almost directly mapped to + * the levels that exist in the Google Android platform. The following table + * shows the mapping implemented by this logger. + *

+ * + * + * + * + * + * + * + *
SLF4JAndroid
TRACE{@link Log#VERBOSE}
DEBUG{@link Log#DEBUG}
INFO{@link Log#INFO}
WARN{@link Log#WARN}
ERROR{@link Log#ERROR}
+ * + * @author Thorsten Möller + */ +public class AndroidLogger extends MarkerIgnoringBase { + private static final long serialVersionUID = -1227274521521287937L; + + /** + * Package access allows only {@link AndroidLoggerFactory} to instantiate + * SimpleLogger instances. + */ + AndroidLogger(final String name) { + //this.name = name; + this.name = SSHD.TAG; + } + + /* @see org.slf4j.Logger#isTraceEnabled() */ + public boolean isTraceEnabled() { + // return Log.isLoggable(name, Log.VERBOSE); + return true; + } + + /* @see org.slf4j.Logger#trace(java.lang.String) */ + public void trace(final String msg) { + Log.i(name, msg); + } + + /* @see org.slf4j.Logger#trace(java.lang.String, java.lang.Object) */ + public void trace(final String format, final Object param1) { + Log.i(name, format(format, param1, null)); + } + + /* @see org.slf4j.Logger#trace(java.lang.String, java.lang.Object, java.lang.Object) */ + public void trace(final String format, final Object param1, final Object param2) { + Log.i(name, format(format, param1, param2)); + } + + /* @see org.slf4j.Logger#trace(java.lang.String, java.lang.Object[]) */ + public void trace(final String format, final Object... arguments) { + Log.i(name, format(format, arguments)); + } + + /* @see org.slf4j.Logger#trace(java.lang.String, java.lang.Throwable) */ + public void trace(final String msg, final Throwable t) { + Log.i(name, msg, t); + } + + /* @see org.slf4j.Logger#isDebugEnabled() */ + public boolean isDebugEnabled() { + // return Log.isLoggable(name, Log.DEBUG); + return true; + } + + /* @see org.slf4j.Logger#debug(java.lang.String) */ + public void debug(final String msg) { + Log.d(name, msg); + } + + /* @see org.slf4j.Logger#debug(java.lang.String, java.lang.Object) */ + public void debug(final String format, final Object arg1) { + Log.d(name, format(format, arg1, null)); + } + + /* @see org.slf4j.Logger#debug(java.lang.String, java.lang.Object, java.lang.Object) */ + public void debug(final String format, final Object param1, final Object param2) { + Log.d(name, format(format, param1, param2)); + } + + /* @see org.slf4j.Logger#debug(java.lang.String, java.lang.Object[]) */ + public void debug(final String format, final Object... arguments) { + Log.d(name, format(format, arguments)); + } + + /* @see org.slf4j.Logger#debug(java.lang.String, java.lang.Throwable) */ + public void debug(final String msg, final Throwable t) { + Log.d(name, msg, t); + } + + /* @see org.slf4j.Logger#isInfoEnabled() */ + public boolean isInfoEnabled() { + //return Log.isLoggable(name, Log.INFO); + return true; + } + + /* @see org.slf4j.Logger#info(java.lang.String) */ + public void info(final String msg) { + Log.i(name, msg); + } + + /* @see org.slf4j.Logger#info(java.lang.String, java.lang.Object) */ + public void info(final String format, final Object arg) { + Log.i(name, format(format, arg, null)); + } + + /* @see org.slf4j.Logger#info(java.lang.String, java.lang.Object, java.lang.Object) */ + public void info(final String format, final Object arg1, final Object arg2) { + Log.i(name, format(format, arg1, arg2)); + } + + /* @see org.slf4j.Logger#info(java.lang.String, java.lang.Object[]) */ + public void info(final String format, final Object... arguments) { + Log.i(name, format(format, arguments)); + } + + /* @see org.slf4j.Logger#info(java.lang.String, java.lang.Throwable) */ + public void info(final String msg, final Throwable t) { + Log.i(name, msg, t); + } + + /* @see org.slf4j.Logger#isWarnEnabled() */ + public boolean isWarnEnabled() { + // return Log.isLoggable(name, Log.WARN); + return true; + } + + /* @see org.slf4j.Logger#warn(java.lang.String) */ + public void warn(final String msg) { + Log.w(name, msg); + } + + /* @see org.slf4j.Logger#warn(java.lang.String, java.lang.Object) */ + public void warn(final String format, final Object arg) { + Log.w(name, format(format, arg, null)); + } + + /* @see org.slf4j.Logger#warn(java.lang.String, java.lang.Object, java.lang.Object) */ + public void warn(final String format, final Object arg1, final Object arg2) { + Log.w(name, format(format, arg1, arg2)); + } + + /* @see org.slf4j.Logger#warn(java.lang.String, java.lang.Object[]) */ + public void warn(final String format, final Object... arguments) { + Log.w(name, format(format, arguments)); + } + + /* @see org.slf4j.Logger#warn(java.lang.String, java.lang.Throwable) */ + public void warn(final String msg, final Throwable t) { + Log.w(name, msg, t); + } + + /* @see org.slf4j.Logger#isErrorEnabled() */ + public boolean isErrorEnabled() { + // return Log.isLoggable(name, Log.ERROR); + return true; + } + + /* @see org.slf4j.Logger#error(java.lang.String) */ + public void error(final String msg) { + Log.e(name, msg); + } + + /* @see org.slf4j.Logger#error(java.lang.String, java.lang.Object) */ + public void error(final String format, final Object arg) { + Log.e(name, format(format, arg, null)); + } + + /* @see org.slf4j.Logger#error(java.lang.String, java.lang.Object, java.lang.Object) */ + public void error(final String format, final Object arg1, final Object arg2) { + Log.e(name, format(format, arg1, arg2)); + } + + /* @see org.slf4j.Logger#error(java.lang.String, java.lang.Object[]) */ + public void error(final String format, final Object... arguments) { + Log.e(name, format(format, arguments)); + } + + /* @see org.slf4j.Logger#error(java.lang.String, java.lang.Throwable) */ + public void error(final String msg, final Throwable t) { + Log.e(name, msg, t); + } + + /** + * For formatted messages substitute arguments. + * + * @param format + * @param arg1 + * @param arg2 + */ + private String format(final String format, final Object arg1, final Object arg2) { + return MessageFormatter.format(format, arg1, arg2).getMessage(); + } + + /** + * For formatted messages substitute arguments. + * + * @param format + * @param args + */ + private String format(final String format, final Object[] args) { + return MessageFormatter.arrayFormat(format, args).getMessage(); + } +} diff --git a/app/src/main/java/org/slf4j/impl/AndroidLoggerFactory.java b/app/src/main/java/org/slf4j/impl/AndroidLoggerFactory.java new file mode 100755 index 0000000..f03ebfe --- /dev/null +++ b/app/src/main/java/org/slf4j/impl/AndroidLoggerFactory.java @@ -0,0 +1,128 @@ +/* + * Created 21.10.2009 + * + * Copyright (c) 2009-2012 SLF4J.ORG + * + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package org.slf4j.impl; + +import java.util.StringTokenizer; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; + +import org.slf4j.ILoggerFactory; + +import android.util.Log; + +/** + * An implementation of {@link ILoggerFactory} which always returns + * {@link AndroidLogger} instances. + * + * @author Thorsten Möler + * @version $Rev:$; $Author:$; $Date:$ + */ +public class AndroidLoggerFactory implements ILoggerFactory +{ + private final ConcurrentMap loggerMap; + + static final int TAG_MAX_LENGTH = 23; // tag names cannot be longer on Android platform + // see also android/system/core/include/cutils/property.h + // and android/frameworks/base/core/jni/android_util_Log.cpp + + public AndroidLoggerFactory() + { + loggerMap = new ConcurrentHashMap(); + } + + /* @see org.slf4j.ILoggerFactory#getLogger(java.lang.String) */ + public AndroidLogger getLogger(final String name) + { + final String tag = forceValidName(name); // fix for bug #173 + + AndroidLogger logger = loggerMap.get(tag); + if (logger != null) return logger; + + logger = new AndroidLogger(tag); + AndroidLogger loggerPutBefore = loggerMap.putIfAbsent(tag, logger); + if (null == loggerPutBefore) + { + if (!tag.equals(name) && Log.isLoggable(AndroidLoggerFactory.class.getSimpleName(), Log.WARN)) + { + Log.i(AndroidLoggerFactory.class.getSimpleName(), new StringBuilder("SLF4J Logger name '") + .append(name) + .append("' exceeds maximum length of ") + .append(TAG_MAX_LENGTH) + .append(" characters; using '") + .append(tag) + .append("' as the Android Log tag instead.") + .toString()); + } + return logger; + } + return loggerPutBefore; + } + + /** + * Trim name in case it exceeds maximum length of {@value #TAG_MAX_LENGTH} characters. + */ + private final String forceValidName(String name) + { + if (name != null && name.length() > TAG_MAX_LENGTH) + { + final StringTokenizer st = new StringTokenizer(name, "."); + if (st.hasMoreTokens()) // note that empty tokens are skipped, i.e., "aa..bb" has tokens "aa", "bb" + { + final StringBuilder sb = new StringBuilder(); + String token; + do + { + token = st.nextToken(); + if (token.length() == 1) // token of one character appended as is + { + sb.append(token); + sb.append('.'); + } + else if (st.hasMoreTokens()) // truncate all but the last token + { + sb.append(token.charAt(0)); + sb.append("*."); + } + else // last token (usually class name) appended as is + { + sb.append(token); + } + } while (st.hasMoreTokens()); + + name = sb.toString(); + } + + // Either we had no useful dot location at all or name still too long. + // Take leading part and append '*' to indicate that it was truncated + if (name.length() > TAG_MAX_LENGTH) + { + name = name.substring(0, TAG_MAX_LENGTH - 1) + '*'; + } + } + return name; + } +} diff --git a/app/src/main/java/org/slf4j/impl/StaticLoggerBinder.java b/app/src/main/java/org/slf4j/impl/StaticLoggerBinder.java new file mode 100755 index 0000000..8233cb5 --- /dev/null +++ b/app/src/main/java/org/slf4j/impl/StaticLoggerBinder.java @@ -0,0 +1,85 @@ +/* + * Created 21.10.2009 + * + * Copyright (c) 2009-2012 SLF4J.ORG + * + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package org.slf4j.impl; + +import org.slf4j.ILoggerFactory; +import org.slf4j.LoggerFactory; +import org.slf4j.spi.LoggerFactoryBinder; + +/** + * The binding of {@link LoggerFactory} class with an actual instance of + * {@link ILoggerFactory} is performed using information returned by this class. + * + * @author Ceki Gülcü + * @author Thorsten Möler + */ +public class StaticLoggerBinder implements LoggerFactoryBinder +{ + + /** + * The unique instance of this class. + */ + private static final StaticLoggerBinder SINGLETON = new StaticLoggerBinder(); + + /** + * Return the singleton of this class. + * + * @return the StaticLoggerBinder singleton + */ + public static final StaticLoggerBinder getSingleton() + { + return SINGLETON; + } + + /** + * Declare the version of the SLF4J API this implementation is compiled + * against. The value of this field is usually modified with each release. + */ + // to avoid constant folding by the compiler, this field must *not* be final + public static String REQUESTED_API_VERSION = "1.6.99"; // !final + + /** + * The ILoggerFactory instance returned by the {@link #getLoggerFactory} + * method should always be the same object + */ + private final ILoggerFactory loggerFactory; + + private StaticLoggerBinder() + { + loggerFactory = new AndroidLoggerFactory(); + } + + public ILoggerFactory getLoggerFactory() + { + return loggerFactory; + } + + public String getLoggerFactoryClassStr() + { + return AndroidLoggerFactory.class.getName(); + } +} diff --git a/app/src/main/java/org/slf4j/impl/StaticMDCBinder.java b/app/src/main/java/org/slf4j/impl/StaticMDCBinder.java new file mode 100755 index 0000000..079d60e --- /dev/null +++ b/app/src/main/java/org/slf4j/impl/StaticMDCBinder.java @@ -0,0 +1,63 @@ +/* + * Created 21.10.2009 + * + * Copyright (c) 2009-2012 SLF4J.ORG + * + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package org.slf4j.impl; + +import org.slf4j.helpers.NOPMDCAdapter; +import org.slf4j.spi.MDCAdapter; + +/** + * This implementation is bound to {@link NOPMDCAdapter}. + * + * @author Ceki Gülcü + * @author Thorsten Möler + */ +public class StaticMDCBinder +{ + + /** + * The unique instance of this class. + */ + public static final StaticMDCBinder SINGLETON = new StaticMDCBinder(); + + private StaticMDCBinder() + { + } + + /** + * Currently this method always returns an instance of + * {@link StaticMDCBinder}. + */ + public MDCAdapter getMDCA() + { + return new NOPMDCAdapter(); + } + + public String getMDCAdapterClassStr() + { + return NOPMDCAdapter.class.getName(); + } +} diff --git a/app/src/main/java/org/slf4j/impl/StaticMarkerBinder.java b/app/src/main/java/org/slf4j/impl/StaticMarkerBinder.java new file mode 100755 index 0000000..2075595 --- /dev/null +++ b/app/src/main/java/org/slf4j/impl/StaticMarkerBinder.java @@ -0,0 +1,73 @@ +/* + * Created 21.10.2009 + * + * Copyright (c) 2009-2012 SLF4J.ORG + * + * All rights reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining + * a copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE + * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION + * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION + * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +package org.slf4j.impl; + +import org.slf4j.IMarkerFactory; +import org.slf4j.MarkerFactory; +import org.slf4j.helpers.BasicMarkerFactory; +import org.slf4j.spi.MarkerFactoryBinder; + +/** + * The binding of {@link MarkerFactory} class with an actual instance of + * {@link IMarkerFactory} is performed using information returned by this class. + * + * @author Ceki Gülcü + * @author Thorsten Möler + */ +public class StaticMarkerBinder implements MarkerFactoryBinder +{ + + /** + * The unique instance of this class. + */ + public static final StaticMarkerBinder SINGLETON = new StaticMarkerBinder(); + + private final IMarkerFactory markerFactory = new BasicMarkerFactory(); + + private StaticMarkerBinder() + { + } + + /** + * Currently this method always returns an instance of + * {@link BasicMarkerFactory}. + */ + public IMarkerFactory getMarkerFactory() + { + return markerFactory; + } + + /** + * Currently, this method returns the class name of + * {@link BasicMarkerFactory}. + */ + public String getMarkerFactoryClassStr() + { + return BasicMarkerFactory.class.getName(); + } + +} diff --git a/app/src/main/java/org/slf4j/impl/package-info.java b/app/src/main/java/org/slf4j/impl/package-info.java new file mode 100644 index 0000000..05dcf6c --- /dev/null +++ b/app/src/main/java/org/slf4j/impl/package-info.java @@ -0,0 +1,3 @@ +/* + * https://github.com/twwwt/slf4j/tree/master/slf4j-android + */ \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_fab_weimi.png b/app/src/main/res/drawable/ic_fab_weimi.png new file mode 100644 index 0000000..8d8647a Binary files /dev/null and b/app/src/main/res/drawable/ic_fab_weimi.png differ diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml new file mode 100644 index 0000000..1adb145 --- /dev/null +++ b/app/src/main/res/layout/activity_main.xml @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher.png b/app/src/main/res/mipmap-hdpi/ic_launcher.png new file mode 100755 index 0000000..1d558b5 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png new file mode 100755 index 0000000..9082cf5 Binary files /dev/null and b/app/src/main/res/mipmap-hdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher.png b/app/src/main/res/mipmap-mdpi/ic_launcher.png new file mode 100755 index 0000000..5fac071 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png new file mode 100755 index 0000000..10d52e7 Binary files /dev/null and b/app/src/main/res/mipmap-mdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher.png b/app/src/main/res/mipmap-xhdpi/ic_launcher.png new file mode 100755 index 0000000..cdb25b5 Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png new file mode 100755 index 0000000..6cb1f3e Binary files /dev/null and b/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png new file mode 100755 index 0000000..203950b Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png new file mode 100755 index 0000000..830f21b Binary files /dev/null and b/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png new file mode 100755 index 0000000..16222ab Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png differ diff --git a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png new file mode 100755 index 0000000..cf545a9 Binary files /dev/null and b/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png differ diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml new file mode 100755 index 0000000..af5b9d9 --- /dev/null +++ b/app/src/main/res/values/colors.xml @@ -0,0 +1,15 @@ + + + #009df1 + #0079f1 + #0059b0 + #238cf4 + #FFF + #B2000000 + #f1f1f1 + #e91e63 + #ec407a + #805677fc + #80738ffe + #808080 + diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml new file mode 100755 index 0000000..8d0e11c --- /dev/null +++ b/app/src/main/res/values/strings.xml @@ -0,0 +1,7 @@ + + SSHDroid + 给app私有文件系统提供ssh服务 + 目标app: + 服务端口: + 独立进程: + diff --git a/app/src/main/res/values/style.xml b/app/src/main/res/values/style.xml new file mode 100755 index 0000000..a526718 --- /dev/null +++ b/app/src/main/res/values/style.xml @@ -0,0 +1,10 @@ + + + + + \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100755 index 0000000..1daa71a --- /dev/null +++ b/build.gradle @@ -0,0 +1,23 @@ +// Top-level build file where you can add configuration options common to all sub-projects/modules. + +buildscript { + repositories { + google() + jcenter() + } + dependencies { + classpath 'com.android.tools.build:gradle:4.0.0' + } +} + +allprojects { + repositories { + jcenter() + google() + maven { url 'https://jitpack.io' } + } +} + +task clean(type: Delete) { + delete rootProject.buildDir +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100755 index 0000000..527d5a7 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,16 @@ +## Project-wide Gradle settings. +# +# For more details on how to configure your build environment visit +# http://www.gradle.org/docs/current/userguide/build_environment.html +# +# Specifies the JVM arguments used for the daemon process. +# The setting is particularly useful for tweaking memory settings. +# Default value: -Xmx1024m -XX:MaxPermSize=256m +# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 +# +# When configured, Gradle will run in incubating parallel mode. +# This option should only be used with decoupled projects. More details, visit +# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects +# org.gradle.parallel=true +#Tue Jul 04 22:35:43 CST 2017 +android.useAndroidX=true diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000..f6b961f Binary files /dev/null and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..46d4d6c --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Thu Jun 18 13:05:53 CST 2020 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip diff --git a/gradlew b/gradlew new file mode 100755 index 0000000..cccdd3d --- /dev/null +++ b/gradlew @@ -0,0 +1,172 @@ +#!/usr/bin/env sh + +############################################################################## +## +## Gradle start up script for UN*X +## +############################################################################## + +# Attempt to set APP_HOME +# Resolve links: $0 may be a link +PRG="$0" +# Need this for relative symlinks. +while [ -h "$PRG" ] ; do + ls=`ls -ld "$PRG"` + link=`expr "$ls" : '.*-> \(.*\)$'` + if expr "$link" : '/.*' > /dev/null; then + PRG="$link" + else + PRG=`dirname "$PRG"`"/$link" + fi +done +SAVED="`pwd`" +cd "`dirname \"$PRG\"`/" >/dev/null +APP_HOME="`pwd -P`" +cd "$SAVED" >/dev/null + +APP_NAME="Gradle" +APP_BASE_NAME=`basename "$0"` + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS="" + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD="maximum" + +warn () { + echo "$*" +} + +die () { + echo + echo "$*" + echo + exit 1 +} + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "`uname`" in + CYGWIN* ) + cygwin=true + ;; + Darwin* ) + darwin=true + ;; + MINGW* ) + msys=true + ;; + NONSTOP* ) + nonstop=true + ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD="java" + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then + MAX_FD_LIMIT=`ulimit -H -n` + if [ $? -eq 0 ] ; then + if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then + MAX_FD="$MAX_FD_LIMIT" + fi + ulimit -n $MAX_FD + if [ $? -ne 0 ] ; then + warn "Could not set maximum file descriptor limit: $MAX_FD" + fi + else + warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" + fi +fi + +# For Darwin, add options to specify how the application appears in the dock +if $darwin; then + GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" +fi + +# For Cygwin, switch paths to Windows format before running java +if $cygwin ; then + APP_HOME=`cygpath --path --mixed "$APP_HOME"` + CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` + JAVACMD=`cygpath --unix "$JAVACMD"` + + # We build the pattern for arguments to be converted via cygpath + ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` + SEP="" + for dir in $ROOTDIRSRAW ; do + ROOTDIRS="$ROOTDIRS$SEP$dir" + SEP="|" + done + OURCYGPATTERN="(^($ROOTDIRS))" + # Add a user-defined pattern to the cygpath arguments + if [ "$GRADLE_CYGPATTERN" != "" ] ; then + OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" + fi + # Now convert the arguments - kludge to limit ourselves to /bin/sh + i=0 + for arg in "$@" ; do + CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` + CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option + + if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition + eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` + else + eval `echo args$i`="\"$arg\"" + fi + i=$((i+1)) + done + case $i in + (0) set -- ;; + (1) set -- "$args0" ;; + (2) set -- "$args0" "$args1" ;; + (3) set -- "$args0" "$args1" "$args2" ;; + (4) set -- "$args0" "$args1" "$args2" "$args3" ;; + (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; + (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; + (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; + (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; + (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; + esac +fi + +# Escape application args +save () { + for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done + echo " " +} +APP_ARGS=$(save "$@") + +# Collect all arguments for the java command, following the shell quoting and substitution rules +eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" + +# by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong +if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then + cd "$(dirname "$0")" +fi + +exec "$JAVACMD" "$@" diff --git a/gradlew.bat b/gradlew.bat new file mode 100755 index 0000000..f955316 --- /dev/null +++ b/gradlew.bat @@ -0,0 +1,84 @@ +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS= + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto init + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto init + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:init +@rem Get command-line arguments, handling Windows variants + +if not "%OS%" == "Windows_NT" goto win9xME_args + +:win9xME_args +@rem Slurp the command line arguments. +set CMD_LINE_ARGS= +set _SKIP=2 + +:win9xME_args_slurp +if "x%~1" == "x" goto execute + +set CMD_LINE_ARGS=%* + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/settings.gradle b/settings.gradle new file mode 100755 index 0000000..e7b4def --- /dev/null +++ b/settings.gradle @@ -0,0 +1 @@ +include ':app'