Permalink
Please sign in to comment.
Showing
with
3,045 additions
and 1 deletion.
- +1 −0 .gradle/2.8/taskArtifacts/cache.properties
- BIN .gradle/2.8/taskArtifacts/cache.properties.lock
- BIN .gradle/2.8/taskArtifacts/fileHashes.bin
- BIN .gradle/2.8/taskArtifacts/fileSnapshots.bin
- BIN .gradle/2.8/taskArtifacts/outputFileStates.bin
- BIN .gradle/2.8/taskArtifacts/taskArtifacts.bin
- +1 −0 DemoMarsdaemon/.gitignore
- +96 −0 DemoMarsdaemon/DemoMarsdaemon.iml
- +22 −0 DemoMarsdaemon/build.gradle
- +17 −0 DemoMarsdaemon/proguard-rules.pro
- +13 −0 DemoMarsdaemon/src/androidTest/java/com/marswin89/marsdaemon/demo/ApplicationTest.java
- +28 −0 DemoMarsdaemon/src/main/AndroidManifest.xml
- +21 −0 DemoMarsdaemon/src/main/java/com/marswin89/marsdaemon/demo/MainActivity.java
- +52 −0 DemoMarsdaemon/src/main/java/com/marswin89/marsdaemon/demo/MyApplication1.java
- +51 −0 DemoMarsdaemon/src/main/java/com/marswin89/marsdaemon/demo/MyApplication2.java
- +17 −0 DemoMarsdaemon/src/main/java/com/marswin89/marsdaemon/demo/Receiver1.java
- +17 −0 DemoMarsdaemon/src/main/java/com/marswin89/marsdaemon/demo/Receiver2.java
- +24 −0 DemoMarsdaemon/src/main/java/com/marswin89/marsdaemon/demo/Service1.java
- +23 −0 DemoMarsdaemon/src/main/java/com/marswin89/marsdaemon/demo/Service2.java
- +19 −0 DemoMarsdaemon/src/main/res/layout/activity_main.xml
- BIN DemoMarsdaemon/src/main/res/mipmap-hdpi/ic_launcher.png
- BIN DemoMarsdaemon/src/main/res/mipmap-mdpi/ic_launcher.png
- BIN DemoMarsdaemon/src/main/res/mipmap-xhdpi/ic_launcher.png
- BIN DemoMarsdaemon/src/main/res/mipmap-xxhdpi/ic_launcher.png
- BIN DemoMarsdaemon/src/main/res/mipmap-xxxhdpi/ic_launcher.png
- +9 −0 DemoMarsdaemon/src/main/res/values-v21/styles.xml
- +6 −0 DemoMarsdaemon/src/main/res/values-w820dp/dimens.xml
- +6 −0 DemoMarsdaemon/src/main/res/values/colors.xml
- +6 −0 DemoMarsdaemon/src/main/res/values/dimens.xml
- +4 −0 DemoMarsdaemon/src/main/res/values/strings.xml
- +20 −0 DemoMarsdaemon/src/main/res/values/styles.xml
- +15 −0 DemoMarsdaemon/src/test/java/com/marswin89/marsdaemon/demo/ExampleUnitTest.java
- +1 −0 LibMarsdaemon/.gitignore
- +87 −0 LibMarsdaemon/LibMarsdaemon.iml
- +30 −0 LibMarsdaemon/build.gradle
- +26 −0 LibMarsdaemon/jni/Android.mk
- +2 −0 LibMarsdaemon/jni/Application.mk
- +21 −0 LibMarsdaemon/jni/com_marswin89_marsdaemon_nativ_NativeDaemonAPI20.h
- +21 −0 LibMarsdaemon/jni/com_marswin89_marsdaemon_nativ_NativeDaemonAPI21.h
- +92 −0 LibMarsdaemon/jni/common.c
- +11 −0 LibMarsdaemon/jni/constant.h
- +118 −0 LibMarsdaemon/jni/daemon.c
- +145 −0 LibMarsdaemon/jni/daemon_api20.c
- +144 −0 LibMarsdaemon/jni/daemon_api21.c
- +16 −0 LibMarsdaemon/jni/log.h
- BIN LibMarsdaemon/libs/armeabi-v7a/libdaemon_api20.so
- BIN LibMarsdaemon/libs/armeabi-v7a/libdaemon_api21.so
- BIN LibMarsdaemon/libs/armeabi/libdaemon_api20.so
- BIN LibMarsdaemon/libs/armeabi/libdaemon_api21.so
- BIN LibMarsdaemon/libs/x86/libdaemon_api20.so
- BIN LibMarsdaemon/libs/x86/libdaemon_api21.so
- +26 −0 LibMarsdaemon/proguard-rules.pro
- +11 −0 LibMarsdaemon/src/main/AndroidManifest.xml
- BIN LibMarsdaemon/src/main/assets/armeabi-v7a/daemon
- BIN LibMarsdaemon/src/main/assets/armeabi/daemon
- BIN LibMarsdaemon/src/main/assets/x86/daemon
- +54 −0 LibMarsdaemon/src/main/java/com/marswin89/marsdaemon/DaemonApplication.java
- +110 −0 LibMarsdaemon/src/main/java/com/marswin89/marsdaemon/DaemonClient.java
- +59 −0 LibMarsdaemon/src/main/java/com/marswin89/marsdaemon/DaemonConfigurations.java
- +20 −0 LibMarsdaemon/src/main/java/com/marswin89/marsdaemon/IDaemonClient.java
- +97 −0 LibMarsdaemon/src/main/java/com/marswin89/marsdaemon/IDaemonStrategy.java
- +28 −0 LibMarsdaemon/src/main/java/com/marswin89/marsdaemon/NativeDaemonBase.java
- +35 −0 LibMarsdaemon/src/main/java/com/marswin89/marsdaemon/PackageUtils.java
- +28 −0 LibMarsdaemon/src/main/java/com/marswin89/marsdaemon/nativ/NativeDaemonAPI20.java
- +27 −0 LibMarsdaemon/src/main/java/com/marswin89/marsdaemon/nativ/NativeDaemonAPI21.java
- +144 −0 LibMarsdaemon/src/main/java/com/marswin89/marsdaemon/strategy/DaemonStrategy21.java
- +204 −0 LibMarsdaemon/src/main/java/com/marswin89/marsdaemon/strategy/DaemonStrategy22.java
- +218 −0 LibMarsdaemon/src/main/java/com/marswin89/marsdaemon/strategy/DaemonStrategy23.java
- +143 −0 LibMarsdaemon/src/main/java/com/marswin89/marsdaemon/strategy/DaemonStrategyUnder21.java
- +215 −0 LibMarsdaemon/src/main/java/com/marswin89/marsdaemon/strategy/DaemonStrategyXiaomi.java
- +3 −0 LibMarsdaemon/src/main/res/values/strings.xml
- +15 −0 LibMarsdaemon/src/test/java/com/marswin89/marsdaemon/ExampleUnitTest.java
- +19 −0 Marsdaemon2.iml
- +87 −1 README.md
- +23 −0 build.gradle
- +12 −0 build/intermediates/dex-cache/cache.xml
- +18 −0 gradle.properties
- BIN gradle/wrapper/gradle-wrapper.jar
- +6 −0 gradle/wrapper/gradle-wrapper.properties
- +160 −0 gradlew
- +90 −0 gradlew.bat
- +10 −0 local.properties
- +1 −0 settings.gradle
1
.gradle/2.8/taskArtifacts/cache.properties
@@ -0,0 +1 @@ | ||
+#Thu Dec 24 18:13:42 CST 2015 |
BIN
.gradle/2.8/taskArtifacts/cache.properties.lock
Binary file not shown.
BIN
.gradle/2.8/taskArtifacts/fileHashes.bin
Binary file not shown.
BIN
.gradle/2.8/taskArtifacts/fileSnapshots.bin
Binary file not shown.
BIN
.gradle/2.8/taskArtifacts/outputFileStates.bin
Binary file not shown.
BIN
.gradle/2.8/taskArtifacts/taskArtifacts.bin
Binary file not shown.
1
DemoMarsdaemon/.gitignore
@@ -0,0 +1 @@ | ||
+/build |
96
DemoMarsdaemon/DemoMarsdaemon.iml
@@ -0,0 +1,96 @@ | ||
+<?xml version="1.0" encoding="UTF-8"?> | ||
+<module external.linked.project.id=":DemoMarsdaemon" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="Marsdaemon2" external.system.module.version="unspecified" type="JAVA_MODULE" version="4"> | ||
+ <component name="FacetManager"> | ||
+ <facet type="android-gradle" name="Android-Gradle"> | ||
+ <configuration> | ||
+ <option name="GRADLE_PROJECT_PATH" value=":DemoMarsdaemon" /> | ||
+ </configuration> | ||
+ </facet> | ||
+ <facet type="android" name="Android"> | ||
+ <configuration> | ||
+ <option name="SELECTED_BUILD_VARIANT" value="debug" /> | ||
+ <option name="SELECTED_TEST_ARTIFACT" value="_android_test_" /> | ||
+ <option name="ASSEMBLE_TASK_NAME" value="assembleDebug" /> | ||
+ <option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" /> | ||
+ <option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugAndroidTest" /> | ||
+ <option name="COMPILE_JAVA_TEST_TASK_NAME" value="compileDebugAndroidTestSources" /> | ||
+ <afterSyncTasks> | ||
+ <task>generateDebugAndroidTestSources</task> | ||
+ <task>generateDebugSources</task> | ||
+ </afterSyncTasks> | ||
+ <option name="ALLOW_USER_CONFIGURATION" value="false" /> | ||
+ <option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" /> | ||
+ <option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" /> | ||
+ <option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" /> | ||
+ <option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" /> | ||
+ </configuration> | ||
+ </facet> | ||
+ </component> | ||
+ <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false"> | ||
+ <output url="file://$MODULE_DIR$/build/intermediates/classes/debug" /> | ||
+ <exclude-output /> | ||
+ <content url="file://$MODULE_DIR$"> | ||
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/blame" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/debug" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/dex" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/appcompat-v7/23.1.1/jars" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/design/23.1.1/jars" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/recyclerview-v7/23.1.1/jars" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/exploded-aar/com.android.support/support-v4/23.1.1/jars" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/manifests" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/pre-dexed" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/restart-dex" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/tmp" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/outputs" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/tmp" /> | ||
+ </content> | ||
+ <orderEntry type="jdk" jdkName="Android API 23 Platform" jdkType="Android SDK" /> | ||
+ <orderEntry type="sourceFolder" forTests="false" /> | ||
+ <orderEntry type="library" exported="" name="recyclerview-v7-23.1.1" level="project" /> | ||
+ <orderEntry type="library" exported="" name="support-annotations-23.1.1" level="project" /> | ||
+ <orderEntry type="library" exported="" name="support-v4-23.1.1" level="project" /> | ||
+ <orderEntry type="library" exported="" name="design-23.1.1" level="project" /> | ||
+ <orderEntry type="library" exported="" name="appcompat-v7-23.1.1" level="project" /> | ||
+ <orderEntry type="module" module-name="LibMarsdaemon" exported="" /> | ||
+ </component> | ||
+</module> |
22
DemoMarsdaemon/build.gradle
@@ -0,0 +1,22 @@ | ||
+apply plugin: 'com.android.application' | ||
+ | ||
+android { | ||
+ compileSdkVersion 23 | ||
+ buildToolsVersion "23.0.2" | ||
+ | ||
+ defaultConfig { | ||
+ applicationId "com.marswin89.marsdaemon.demo" | ||
+ minSdkVersion 10 | ||
+ targetSdkVersion 23 | ||
+ versionCode 1 | ||
+ versionName "1.0" | ||
+ } | ||
+} | ||
+ | ||
+dependencies { | ||
+ compile fileTree(dir: 'libs', include: ['*.jar']) | ||
+ testCompile 'junit:junit:4.12' | ||
+ compile 'com.android.support:appcompat-v7:23.1.1' | ||
+ compile 'com.android.support:design:23.1.1' | ||
+ compile project(':LibMarsdaemon') | ||
+} |
17
DemoMarsdaemon/proguard-rules.pro
@@ -0,0 +1,17 @@ | ||
+# Add project specific ProGuard rules here. | ||
+# By default, the flags in this file are appended to flags specified | ||
+# in /Users/guoyang/Developer/android-sdk-macosx/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 *; | ||
+#} |
13
DemoMarsdaemon/src/androidTest/java/com/marswin89/marsdaemon/demo/ApplicationTest.java
@@ -0,0 +1,13 @@ | ||
+package com.marswin89.marsdaemon.demo; | ||
+ | ||
+import android.app.Application; | ||
+import android.test.ApplicationTestCase; | ||
+ | ||
+/** | ||
+ * <a href="http://d.android.com/tools/testing/testing_android.html">Testing Fundamentals</a> | ||
+ */ | ||
+public class ApplicationTest extends ApplicationTestCase<Application> { | ||
+ public ApplicationTest() { | ||
+ super(Application.class); | ||
+ } | ||
+} |
28
DemoMarsdaemon/src/main/AndroidManifest.xml
@@ -0,0 +1,28 @@ | ||
+<?xml version="1.0" encoding="utf-8"?> | ||
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||
+ package="com.marswin89.marsdaemon.demo"> | ||
+ | ||
+ <application | ||
+ android:name=".MyApplication1" | ||
+ android:allowBackup="true" | ||
+ android:icon="@mipmap/ic_launcher" | ||
+ android:label="@string/app_name" | ||
+ android:supportsRtl="true" | ||
+ android:theme="@style/AppTheme"> | ||
+ <activity | ||
+ android:name="com.marswin89.marsdaemon.demo.MainActivity" | ||
+ android:label="@string/app_name" | ||
+ android:theme="@android:style/Theme.NoTitleBar"> | ||
+ <intent-filter> | ||
+ <action android:name="android.intent.action.MAIN" /> | ||
+ <category android:name="android.intent.category.LAUNCHER" /> | ||
+ </intent-filter> | ||
+ </activity> | ||
+ | ||
+ <service android:name=".Service1" android:process=":process1"/> | ||
+ <receiver android:name=".Receiver1" android:process=":process1"/> | ||
+ <service android:name=".Service2" android:process=":process2"/> | ||
+ <receiver android:name=".Receiver2" android:process=":process2"/> | ||
+ </application> | ||
+ | ||
+</manifest> |
21
DemoMarsdaemon/src/main/java/com/marswin89/marsdaemon/demo/MainActivity.java
@@ -0,0 +1,21 @@ | ||
+package com.marswin89.marsdaemon.demo; | ||
+ | ||
+import android.app.Activity; | ||
+import android.content.Intent; | ||
+import android.os.Bundle; | ||
+ | ||
+/** | ||
+ * | ||
+ * Created by Mars on 12/24/15. | ||
+ */ | ||
+public class MainActivity extends Activity { | ||
+ | ||
+ @Override | ||
+ protected void onCreate(Bundle savedInstanceState) { | ||
+ super.onCreate(savedInstanceState); | ||
+ setContentView(R.layout.activity_main); | ||
+ | ||
+ //you have to start the service once. | ||
+ startService(new Intent(MainActivity.this, Service1.class)); | ||
+ } | ||
+} |
52
DemoMarsdaemon/src/main/java/com/marswin89/marsdaemon/demo/MyApplication1.java
@@ -0,0 +1,52 @@ | ||
+package com.marswin89.marsdaemon.demo; | ||
+ | ||
+import android.content.Context; | ||
+ | ||
+import com.marswin89.marsdaemon.DaemonApplication; | ||
+import com.marswin89.marsdaemon.DaemonConfigurations; | ||
+ | ||
+/** | ||
+ * Implementation 1<br/> | ||
+ * override one method is ok.<br/> | ||
+ * | ||
+ * Created by Mars on 12/24/15. | ||
+ */ | ||
+public class MyApplication1 extends DaemonApplication { | ||
+ /** | ||
+ * you can override this method instead of {@link android.app.Application attachBaseContext} | ||
+ * @param base | ||
+ */ | ||
+ @Override | ||
+ public void attachBaseContextByDaemon(Context base) { | ||
+ super.attachBaseContextByDaemon(base); | ||
+ } | ||
+ | ||
+ | ||
+ /** | ||
+ * give the configuration to lib in this callback | ||
+ * @return | ||
+ */ | ||
+ @Override | ||
+ protected DaemonConfigurations getDaemonConfigurations() { | ||
+ DaemonConfigurations.DaemonConfiguration configuration1 = new DaemonConfigurations.DaemonConfiguration("com.marswin89.marsdaemon.demo:process1", Service1.class.getCanonicalName(), Receiver1.class.getCanonicalName()); | ||
+ DaemonConfigurations.DaemonConfiguration configuration2 = new DaemonConfigurations.DaemonConfiguration("com.marswin89.marsdaemon.demo:process2", Service2.class.getCanonicalName(), Receiver2.class.getCanonicalName()); | ||
+ DaemonConfigurations.DaemonListener listener = new MyDaemonListener(); | ||
+ //return new DaemonConfigurations(configuration1, configuration2);//listener can be null | ||
+ return new DaemonConfigurations(configuration1, configuration2, listener); | ||
+ } | ||
+ | ||
+ | ||
+ class MyDaemonListener implements DaemonConfigurations.DaemonListener{ | ||
+ @Override | ||
+ public void onPersistentStart(Context context) { | ||
+ } | ||
+ | ||
+ @Override | ||
+ public void onDaemonAssistantStart(Context context) { | ||
+ } | ||
+ | ||
+ @Override | ||
+ public void onWatchDaemonDaed() { | ||
+ } | ||
+ } | ||
+} |
51
DemoMarsdaemon/src/main/java/com/marswin89/marsdaemon/demo/MyApplication2.java
@@ -0,0 +1,51 @@ | ||
+package com.marswin89.marsdaemon.demo; | ||
+ | ||
+import android.app.Application; | ||
+import android.content.Context; | ||
+ | ||
+import com.marswin89.marsdaemon.DaemonApplication; | ||
+import com.marswin89.marsdaemon.DaemonClient; | ||
+import com.marswin89.marsdaemon.DaemonConfigurations; | ||
+ | ||
+/** | ||
+ * Implementation 2<br/> | ||
+ * if you have to extends other Application, use this method.<br/> | ||
+ * | ||
+ * Created by Mars on 12/24/15. | ||
+ */ | ||
+public class MyApplication2 extends Application { | ||
+ | ||
+ private DaemonClient mDaemonClient; | ||
+ | ||
+ @Override | ||
+ protected void attachBaseContext(Context base) { | ||
+ super.attachBaseContext(base); | ||
+ mDaemonClient = new DaemonClient(createDaemonConfigurations()); | ||
+ mDaemonClient.onAttachBaseContext(base); | ||
+ } | ||
+ | ||
+ | ||
+ | ||
+ private DaemonConfigurations createDaemonConfigurations(){ | ||
+ DaemonConfigurations.DaemonConfiguration configuration1 = new DaemonConfigurations.DaemonConfiguration("com.marswin89.marsdaemon.demo:process1", Service1.class.getCanonicalName(), Receiver1.class.getCanonicalName()); | ||
+ DaemonConfigurations.DaemonConfiguration configuration2 = new DaemonConfigurations.DaemonConfiguration("com.marswin89.marsdaemon.demo:process2", Service2.class.getCanonicalName(), Receiver2.class.getCanonicalName()); | ||
+ DaemonConfigurations.DaemonListener listener = new MyDaemonListener(); | ||
+ //return new DaemonConfigurations(configuration1, configuration2);//listener can be null | ||
+ return new DaemonConfigurations(configuration1, configuration2, listener); | ||
+ } | ||
+ | ||
+ | ||
+ class MyDaemonListener implements DaemonConfigurations.DaemonListener{ | ||
+ @Override | ||
+ public void onPersistentStart(Context context) { | ||
+ } | ||
+ | ||
+ @Override | ||
+ public void onDaemonAssistantStart(Context context) { | ||
+ } | ||
+ | ||
+ @Override | ||
+ public void onWatchDaemonDaed() { | ||
+ } | ||
+ } | ||
+} |
17
DemoMarsdaemon/src/main/java/com/marswin89/marsdaemon/demo/Receiver1.java
@@ -0,0 +1,17 @@ | ||
+package com.marswin89.marsdaemon.demo; | ||
+ | ||
+import android.content.BroadcastReceiver; | ||
+import android.content.Context; | ||
+import android.content.Intent; | ||
+ | ||
+/** | ||
+ * DO NOT do anything in this Receiver!<br/> | ||
+ * | ||
+ * Created by Mars on 12/24/15. | ||
+ */ | ||
+public class Receiver1 extends BroadcastReceiver { | ||
+ @Override | ||
+ public void onReceive(Context context, Intent intent) { | ||
+ | ||
+ } | ||
+} |
17
DemoMarsdaemon/src/main/java/com/marswin89/marsdaemon/demo/Receiver2.java
@@ -0,0 +1,17 @@ | ||
+package com.marswin89.marsdaemon.demo; | ||
+ | ||
+import android.content.BroadcastReceiver; | ||
+import android.content.Context; | ||
+import android.content.Intent; | ||
+ | ||
+/** | ||
+ * DO NOT do anything in this Receiver!<br/> | ||
+ * | ||
+ * Created by Mars on 12/24/15. | ||
+ */ | ||
+public class Receiver2 extends BroadcastReceiver { | ||
+ @Override | ||
+ public void onReceive(Context context, Intent intent) { | ||
+ | ||
+ } | ||
+} |
24
DemoMarsdaemon/src/main/java/com/marswin89/marsdaemon/demo/Service1.java
@@ -0,0 +1,24 @@ | ||
+package com.marswin89.marsdaemon.demo; | ||
+ | ||
+import android.app.Service; | ||
+import android.content.Intent; | ||
+import android.os.IBinder; | ||
+ | ||
+/** | ||
+ * This Service is Persistent Service. Do some what you want to do here.<br/> | ||
+ * | ||
+ * Created by Mars on 12/24/15. | ||
+ */ | ||
+public class Service1 extends Service{ | ||
+ | ||
+ @Override | ||
+ public void onCreate() { | ||
+ super.onCreate(); | ||
+ //TODO do some thing what you want.. | ||
+ } | ||
+ | ||
+ @Override | ||
+ public IBinder onBind(Intent intent) { | ||
+ return null; | ||
+ } | ||
+} |
23
DemoMarsdaemon/src/main/java/com/marswin89/marsdaemon/demo/Service2.java
@@ -0,0 +1,23 @@ | ||
+package com.marswin89.marsdaemon.demo; | ||
+ | ||
+import android.app.Service; | ||
+import android.content.Intent; | ||
+import android.os.IBinder; | ||
+ | ||
+/** | ||
+ * DO NOT do anything in this Service!<br/> | ||
+ * | ||
+ * Created by Mars on 12/24/15. | ||
+ */ | ||
+public class Service2 extends Service{ | ||
+ | ||
+ @Override | ||
+ public IBinder onBind(Intent intent) { | ||
+ return null; | ||
+ } | ||
+ | ||
+ @Override | ||
+ public int onStartCommand(Intent intent, int flags, int startId) { | ||
+ return Service.START_NOT_STICKY; | ||
+ } | ||
+} |
19
DemoMarsdaemon/src/main/res/layout/activity_main.xml
@@ -0,0 +1,19 @@ | ||
+<?xml version="1.0" encoding="utf-8"?> | ||
+<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" | ||
+ xmlns:tools="http://schemas.android.com/tools" | ||
+ android:layout_width="match_parent" | ||
+ android:layout_height="match_parent" | ||
+ android:fitsSystemWindows="true" | ||
+ android:background="@android:color/black" | ||
+ tools:context="com.marswin89.marsdaemon.demo.MainActivity"> | ||
+ | ||
+ <TextView | ||
+ android:layout_height="wrap_content" | ||
+ android:layout_width="wrap_content" | ||
+ android:textSize="30sp" | ||
+ android:text="@string/hello" | ||
+ android:layout_centerInParent="true" | ||
+ android:textColor="@android:color/white" | ||
+ /> | ||
+ | ||
+</RelativeLayout> |
BIN
DemoMarsdaemon/src/main/res/mipmap-hdpi/ic_launcher.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN
DemoMarsdaemon/src/main/res/mipmap-mdpi/ic_launcher.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN
DemoMarsdaemon/src/main/res/mipmap-xhdpi/ic_launcher.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN
DemoMarsdaemon/src/main/res/mipmap-xxhdpi/ic_launcher.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN
DemoMarsdaemon/src/main/res/mipmap-xxxhdpi/ic_launcher.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9
DemoMarsdaemon/src/main/res/values-v21/styles.xml
@@ -0,0 +1,9 @@ | ||
+<resources> | ||
+ | ||
+ <style name="AppTheme.NoActionBar"> | ||
+ <item name="windowActionBar">false</item> | ||
+ <item name="windowNoTitle">true</item> | ||
+ <item name="android:windowDrawsSystemBarBackgrounds">true</item> | ||
+ <item name="android:statusBarColor">@android:color/transparent</item> | ||
+ </style> | ||
+</resources> |
6
DemoMarsdaemon/src/main/res/values-w820dp/dimens.xml
@@ -0,0 +1,6 @@ | ||
+<resources> | ||
+ <!-- Example customization of dimensions originally defined in res/values/dimens.xml | ||
+ (such as screen margins) for screens with more than 820dp of available width. This | ||
+ would include 7" and 10" devices in landscape (~960dp and ~1280dp respectively). --> | ||
+ <dimen name="activity_horizontal_margin">64dp</dimen> | ||
+</resources> |
6
DemoMarsdaemon/src/main/res/values/colors.xml
@@ -0,0 +1,6 @@ | ||
+<?xml version="1.0" encoding="utf-8"?> | ||
+<resources> | ||
+ <color name="colorPrimary">#3F51B5</color> | ||
+ <color name="colorPrimaryDark">#303F9F</color> | ||
+ <color name="colorAccent">#FF4081</color> | ||
+</resources> |
6
DemoMarsdaemon/src/main/res/values/dimens.xml
@@ -0,0 +1,6 @@ | ||
+<resources> | ||
+ <!-- Default screen margins, per the Android Design guidelines. --> | ||
+ <dimen name="activity_horizontal_margin">16dp</dimen> | ||
+ <dimen name="activity_vertical_margin">16dp</dimen> | ||
+ <dimen name="fab_margin">16dp</dimen> | ||
+</resources> |
4
DemoMarsdaemon/src/main/res/values/strings.xml
@@ -0,0 +1,4 @@ | ||
+<resources> | ||
+ <string name="hello">Hello, this is Mars.</string> | ||
+ <string name="app_name">MarsDaemon</string> | ||
+</resources> |
20
DemoMarsdaemon/src/main/res/values/styles.xml
@@ -0,0 +1,20 @@ | ||
+<resources> | ||
+ | ||
+ <!-- Base application theme. --> | ||
+ <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> | ||
+ <!-- Customize your theme here. --> | ||
+ <item name="colorPrimary">@color/colorPrimary</item> | ||
+ <item name="colorPrimaryDark">@color/colorPrimaryDark</item> | ||
+ <item name="colorAccent">@color/colorAccent</item> | ||
+ </style> | ||
+ | ||
+ <style name="AppTheme.NoActionBar"> | ||
+ <item name="windowActionBar">false</item> | ||
+ <item name="windowNoTitle">true</item> | ||
+ </style> | ||
+ | ||
+ <style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" /> | ||
+ | ||
+ <style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" /> | ||
+ | ||
+</resources> |
15
DemoMarsdaemon/src/test/java/com/marswin89/marsdaemon/demo/ExampleUnitTest.java
@@ -0,0 +1,15 @@ | ||
+package com.marswin89.marsdaemon.demo; | ||
+ | ||
+import org.junit.Test; | ||
+ | ||
+import static org.junit.Assert.*; | ||
+ | ||
+/** | ||
+ * To work on unit tests, switch the Test Artifact in the Build Variants view. | ||
+ */ | ||
+public class ExampleUnitTest { | ||
+ @Test | ||
+ public void addition_isCorrect() throws Exception { | ||
+ assertEquals(4, 2 + 2); | ||
+ } | ||
+} |
1
LibMarsdaemon/.gitignore
@@ -0,0 +1 @@ | ||
+/build |
87
LibMarsdaemon/LibMarsdaemon.iml
@@ -0,0 +1,87 @@ | ||
+<?xml version="1.0" encoding="UTF-8"?> | ||
+<module external.linked.project.id=":LibMarsdaemon" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$/.." external.system.id="GRADLE" external.system.module.group="Marsdaemon2" external.system.module.version="unspecified" type="JAVA_MODULE" version="4"> | ||
+ <component name="FacetManager"> | ||
+ <facet type="android-gradle" name="Android-Gradle"> | ||
+ <configuration> | ||
+ <option name="GRADLE_PROJECT_PATH" value=":LibMarsdaemon" /> | ||
+ </configuration> | ||
+ </facet> | ||
+ <facet type="android" name="Android"> | ||
+ <configuration> | ||
+ <option name="SELECTED_BUILD_VARIANT" value="debug" /> | ||
+ <option name="SELECTED_TEST_ARTIFACT" value="_android_test_" /> | ||
+ <option name="ASSEMBLE_TASK_NAME" value="assembleDebug" /> | ||
+ <option name="COMPILE_JAVA_TASK_NAME" value="compileDebugSources" /> | ||
+ <option name="ASSEMBLE_TEST_TASK_NAME" value="assembleDebugAndroidTest" /> | ||
+ <option name="COMPILE_JAVA_TEST_TASK_NAME" value="compileDebugAndroidTestSources" /> | ||
+ <afterSyncTasks> | ||
+ <task>generateDebugAndroidTestSources</task> | ||
+ <task>generateDebugSources</task> | ||
+ </afterSyncTasks> | ||
+ <option name="ALLOW_USER_CONFIGURATION" value="false" /> | ||
+ <option name="MANIFEST_FILE_RELATIVE_PATH" value="/src/main/AndroidManifest.xml" /> | ||
+ <option name="RES_FOLDER_RELATIVE_PATH" value="/src/main/res" /> | ||
+ <option name="RES_FOLDERS_RELATIVE_PATH" value="file://$MODULE_DIR$/src/main/res" /> | ||
+ <option name="ASSETS_FOLDER_RELATIVE_PATH" value="/src/main/assets" /> | ||
+ <option name="LIBRARY_PROJECT" value="true" /> | ||
+ </configuration> | ||
+ </facet> | ||
+ </component> | ||
+ <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="false"> | ||
+ <output url="file://$MODULE_DIR$/build/intermediates/classes/debug" /> | ||
+ <exclude-output /> | ||
+ <content url="file://$MODULE_DIR$"> | ||
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/debug" isTestSource="false" generated="true" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/debug" isTestSource="false" generated="true" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/debug" isTestSource="false" generated="true" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/debug" isTestSource="false" generated="true" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/debug" type="java-resource" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/debug" type="java-resource" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/r/androidTest/debug" isTestSource="true" generated="true" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/aidl/androidTest/debug" isTestSource="true" generated="true" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/buildConfig/androidTest/debug" isTestSource="true" generated="true" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/source/rs/androidTest/debug" isTestSource="true" generated="true" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/res/rs/androidTest/debug" type="java-test-resource" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/build/generated/res/resValues/androidTest/debug" type="java-test-resource" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/res" type="java-resource" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/resources" type="java-resource" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/assets" type="java-resource" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/aidl" isTestSource="false" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/java" isTestSource="false" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/jni" isTestSource="false" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/debug/rs" isTestSource="false" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/main/res" type="java-resource" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/main/resources" type="java-resource" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/main/assets" type="java-resource" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/main/aidl" isTestSource="false" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/main/java" isTestSource="false" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/main/jni" isTestSource="false" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/main/rs" isTestSource="false" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/res" type="java-test-resource" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/resources" type="java-test-resource" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/assets" type="java-test-resource" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/aidl" isTestSource="true" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/java" isTestSource="true" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/jni" isTestSource="true" /> | ||
+ <sourceFolder url="file://$MODULE_DIR$/src/androidTest/rs" isTestSource="true" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/annotations" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/assets" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/bundles" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/classes" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/dependency-cache" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/incremental" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/lint" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/proguard-rules" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/res" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/rs" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/intermediates/symbols" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/outputs" /> | ||
+ <excludeFolder url="file://$MODULE_DIR$/build/tmp" /> | ||
+ </content> | ||
+ <orderEntry type="jdk" jdkName="Android API 23 Platform" jdkType="Android SDK" /> | ||
+ <orderEntry type="sourceFolder" forTests="false" /> | ||
+ <orderEntry type="library" exported="" name="support-annotations-23.1.1" level="project" /> | ||
+ <orderEntry type="library" exported="" name="support-v4-23.1.1" level="project" /> | ||
+ <orderEntry type="library" exported="" name="appcompat-v7-23.1.1" level="project" /> | ||
+ </component> | ||
+</module> |
30
LibMarsdaemon/build.gradle
@@ -0,0 +1,30 @@ | ||
+apply plugin: 'com.android.library' | ||
+ | ||
+android { | ||
+ compileSdkVersion 23 | ||
+ buildToolsVersion "23.0.2" | ||
+ | ||
+ defaultConfig { | ||
+ minSdkVersion 10 | ||
+ targetSdkVersion 23 | ||
+ versionCode 1 | ||
+ versionName "1.0" | ||
+ } | ||
+ buildTypes { | ||
+ release { | ||
+ minifyEnabled false | ||
+ proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | ||
+ } | ||
+ } | ||
+ sourceSets { | ||
+ main { | ||
+ jniLibs.srcDirs =['libs'] | ||
+ } | ||
+ } | ||
+} | ||
+ | ||
+dependencies { | ||
+ compile fileTree(dir: 'libs', include: ['*.jar']) | ||
+ testCompile 'junit:junit:4.12' | ||
+ compile 'com.android.support:appcompat-v7:23.1.1' | ||
+} |
26
LibMarsdaemon/jni/Android.mk
@@ -0,0 +1,26 @@ | ||
+LOCAL_PATH := $(call my-dir) | ||
+include $(CLEAR_VARS) | ||
+LOCAL_MODULE := daemon_api20 | ||
+LOCAL_SRC_FILES := daemon_api20.c \ | ||
+ common.c | ||
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include | ||
+LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog -lm -lz | ||
+include $(BUILD_SHARED_LIBRARY) | ||
+ | ||
+include $(CLEAR_VARS) | ||
+LOCAL_MODULE := daemon_api21 | ||
+LOCAL_SRC_FILES := daemon_api21.c \ | ||
+ common.c | ||
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include | ||
+LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -llog -lm -lz | ||
+include $(BUILD_SHARED_LIBRARY) | ||
+ | ||
+include $(CLEAR_VARS) | ||
+LOCAL_MODULE := daemon | ||
+LOCAL_SRC_FILES := daemon.c | ||
+LOCAL_CFLAGS += -pie -fPIE | ||
+LOCAL_LDFLAGS += -pie -fPIE | ||
+LOCAL_C_INCLUDES := $(LOCAL_PATH)/include | ||
+LOCAL_LDLIBS += -L$(SYSROOT)/usr/lib -llog -lm -lz | ||
+include $(BUILD_EXECUTABLE) | ||
+ |
2
LibMarsdaemon/jni/Application.mk
@@ -0,0 +1,2 @@ | ||
+APP_ABI := armeabi armeabi-v7a x86 | ||
+APP_PLATFORM := android-15 |
21
LibMarsdaemon/jni/com_marswin89_marsdaemon_nativ_NativeDaemonAPI20.h
@@ -0,0 +1,21 @@ | ||
+/* DO NOT EDIT THIS FILE - it is machine generated */ | ||
+#include <jni.h> | ||
+/* Header for class com_marswin89_marsdaemon_nativ_NativeDaemonAPI20 */ | ||
+ | ||
+#ifndef _Included_com_marswin89_marsdaemon_nativ_NativeDaemonAPI20 | ||
+#define _Included_com_marswin89_marsdaemon_nativ_NativeDaemonAPI20 | ||
+#ifdef __cplusplus | ||
+extern "C" { | ||
+#endif | ||
+/* | ||
+ * Class: com_marswin89_marsdaemon_nativ_NativeDaemonAPI20 | ||
+ * Method: doDaemon | ||
+ * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V | ||
+ */ | ||
+JNIEXPORT void JNICALL Java_com_marswin89_marsdaemon_nativ_NativeDaemonAPI20_doDaemon | ||
+ (JNIEnv *, jobject, jstring, jstring, jstring); | ||
+ | ||
+#ifdef __cplusplus | ||
+} | ||
+#endif | ||
+#endif |
21
LibMarsdaemon/jni/com_marswin89_marsdaemon_nativ_NativeDaemonAPI21.h
@@ -0,0 +1,21 @@ | ||
+/* DO NOT EDIT THIS FILE - it is machine generated */ | ||
+#include <jni.h> | ||
+/* Header for class com_marswin89_marsdaemon_nativ_NativeDaemonAPI21 */ | ||
+ | ||
+#ifndef _Included_com_marswin89_marsdaemon_nativ_NativeDaemonAPI21 | ||
+#define _Included_com_marswin89_marsdaemon_nativ_NativeDaemonAPI21 | ||
+#ifdef __cplusplus | ||
+extern "C" { | ||
+#endif | ||
+/* | ||
+ * Class: com_marswin89_marsdaemon_nativ_NativeDaemonAPI21 | ||
+ * Method: doDaemon | ||
+ * Signature: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)V | ||
+ */ | ||
+JNIEXPORT void JNICALL Java_com_marswin89_marsdaemon_nativ_NativeDaemonAPI21_doDaemon | ||
+ (JNIEnv *, jobject, jstring, jstring, jstring, jstring); | ||
+ | ||
+#ifdef __cplusplus | ||
+} | ||
+#endif | ||
+#endif |
92
LibMarsdaemon/jni/common.c
@@ -0,0 +1,92 @@ | ||
+/* | ||
+ * File : daemon_api21.c | ||
+ * Author : Mars Kwok | ||
+ * Date : Jul. 21, 2015 | ||
+ * Description : common method here | ||
+ * | ||
+ * Copyright (C) Mars Kwok<Marswin89@gmail.com> | ||
+ * | ||
+ */ | ||
+#include <stdlib.h> | ||
+#include <stdio.h> | ||
+#include <sys/inotify.h> | ||
+#include <fcntl.h> | ||
+#include <sys/stat.h> | ||
+ | ||
+#include "log.h" | ||
+ | ||
+/** | ||
+ * get the android version code | ||
+ */ | ||
+int get_version(){ | ||
+ char value[8] = ""; | ||
+ __system_property_get("ro.build.version.sdk", value); | ||
+ return atoi(value); | ||
+} | ||
+ | ||
+/** | ||
+ * stitch three string to one | ||
+ */ | ||
+char *str_stitching(const char *str1, const char *str2, const char *str3){ | ||
+ char *result; | ||
+ result = (char*) malloc(strlen(str1) + strlen(str2) + strlen(str3) + 1); | ||
+ if (!result){ | ||
+ return NULL; | ||
+ } | ||
+ strcpy(result, str1); | ||
+ strcat(result, str2); | ||
+ strcat(result, str3); | ||
+ return result; | ||
+} | ||
+ | ||
+/** | ||
+ * get android context | ||
+ */ | ||
+jobject get_context(JNIEnv* env, jobject jobj){ | ||
+ jclass thiz_cls = (*env)->GetObjectClass(env, jobj); | ||
+ jfieldID context_field = (*env)->GetFieldID(env, thiz_cls, "mContext", "Landroid/content/Context;"); | ||
+ return (*env)->GetObjectField(env, jobj, context_field); | ||
+} | ||
+ | ||
+ | ||
+char* get_package_name(JNIEnv* env, jobject jobj){ | ||
+ jobject context_obj = get_context(env, jobj); | ||
+ jclass context_cls = (*env)->GetObjectClass(env, context_obj); | ||
+ jmethodID getpackagename_method = (*env)->GetMethodID(jobj, context_cls, "getPackageName", "()Ljava/lang/String;"); | ||
+ jstring package_name = (jstring)(*env)->CallObjectMethod(env, context_obj, getpackagename_method); | ||
+ return (char*)(*env)->GetStringUTFChars(env, package_name, 0); | ||
+} | ||
+ | ||
+ | ||
+/** | ||
+ * call java callback | ||
+ */ | ||
+void java_callback(JNIEnv* env, jobject jobj, char* method_name){ | ||
+ jclass cls = (*env)->GetObjectClass(env, jobj); | ||
+ jmethodID cb_method = (*env)->GetMethodID(env, cls, method_name, "()V"); | ||
+ (*env)->CallVoidMethod(env, jobj, cb_method); | ||
+} | ||
+ | ||
+/** | ||
+ * start a android service | ||
+ */ | ||
+void start_service(char* package_name, char* service_name){ | ||
+ pid_t pid = fork(); | ||
+ if(pid < 0){ | ||
+ //error, do nothing... | ||
+ }else if(pid == 0){ | ||
+ if(package_name == NULL || service_name == NULL){ | ||
+ exit(EXIT_SUCCESS); | ||
+ } | ||
+ int version = get_version(); | ||
+ char* pkg_svc_name = str_stitching(package_name, "/", service_name); | ||
+ if (version >= 17 || version == 0) { | ||
+ execlp("am", "am", "startservice", "--user", "0", "-n", pkg_svc_name, (char *) NULL); | ||
+ } else { | ||
+ execlp("am", "am", "startservice", "-n", pkg_svc_name, (char *) NULL); | ||
+ } | ||
+ exit(EXIT_SUCCESS); | ||
+ }else{ | ||
+ waitpid(pid, NULL, 0); | ||
+ } | ||
+} |
11
LibMarsdaemon/jni/constant.h
@@ -0,0 +1,11 @@ | ||
+#define NATIVE_DAEMON_NAME "mars_d" | ||
+#define BUFFER_SIZE 2048 | ||
+#define DAEMON_CALLBACK_NAME "onDaemonDead" | ||
+#define PARAM_PIPE_1_READ "-p1r" | ||
+#define PARAM_PIPE_1_WRITE "-p1w" | ||
+#define PARAM_PIPE_2_READ "-p2r" | ||
+#define PARAM_PIPE_2_WRITE "-p2w" | ||
+#define PARAM_PKG_NAME "-p" | ||
+#define PARAM_SVC_NAME "-s" | ||
+ | ||
+ |
118
LibMarsdaemon/jni/daemon.c
@@ -0,0 +1,118 @@ | ||
+/* | ||
+ * File : daemon_api21.c | ||
+ * Author : Mars Kwok | ||
+ * Date : Jul. 21, 2015 | ||
+ * Description : This is native process to watch parent process. | ||
+ * | ||
+ * Copyright (C) Mars Kwok<Marswin89@gmail.com> | ||
+ * | ||
+ */ | ||
+#include <stdlib.h> | ||
+#include <unistd.h> | ||
+ | ||
+#include "log.h" | ||
+#include "constant.h" | ||
+ | ||
+ | ||
+/** | ||
+ * get the android version code | ||
+ */ | ||
+int get_version(){ | ||
+ char value[8] = ""; | ||
+ __system_property_get("ro.build.version.sdk", value); | ||
+ return atoi(value); | ||
+} | ||
+ | ||
+char *str_stitching(const char *str1, const char *str2, const char *str3){ | ||
+ char *result; | ||
+ result = (char*) malloc(strlen(str1) + strlen(str2) + strlen(str3) + 1); | ||
+ if (!result){ | ||
+ return NULL; | ||
+ } | ||
+ strcpy(result, str1); | ||
+ strcat(result, str2); | ||
+ strcat(result, str3); | ||
+ return result; | ||
+} | ||
+ | ||
+/** | ||
+ * start a android service | ||
+ */ | ||
+void start_service(char* package_name, char* service_name){ | ||
+ pid_t pid = fork(); | ||
+ if(pid < 0){ | ||
+ //error, do nothing... | ||
+ }else if(pid == 0){ | ||
+ if(package_name == NULL || service_name == NULL){ | ||
+ exit(EXIT_SUCCESS); | ||
+ } | ||
+ int version = get_version(); | ||
+ char* pkg_svc_name = str_stitching(package_name, "/", service_name); | ||
+ if (version >= 17 || version == 0) { | ||
+ execlp("am", "am", "startservice", "--user", "0", "-n", pkg_svc_name, (char *) NULL); | ||
+ } else { | ||
+ execlp("am", "am", "startservice", "-n", pkg_svc_name, (char *) NULL); | ||
+ } | ||
+ exit(EXIT_SUCCESS); | ||
+ }else{ | ||
+ waitpid(pid, NULL, 0); | ||
+ } | ||
+} | ||
+ | ||
+ | ||
+ | ||
+int main(int argc, char *argv[]){ | ||
+ pid_t pid = fork(); | ||
+ if(pid == 0){ | ||
+ setsid(); | ||
+ int pipe_fd1[2]; | ||
+ int pipe_fd2[2]; | ||
+ char* pkg_name; | ||
+ char* svc_name; | ||
+ if(argc < 13){ | ||
+ LOGE("daemon parameters error"); | ||
+ return ; | ||
+ } | ||
+ int i; | ||
+ for (i = 0; i < argc; i ++){ | ||
+ if(argv[i] == NULL){ | ||
+ continue; | ||
+ } | ||
+ if (!strcmp(PARAM_PKG_NAME, argv[i])){ | ||
+ pkg_name = argv[i + 1]; | ||
+ }else if (!strcmp(PARAM_SVC_NAME, argv[i])) { | ||
+ svc_name = argv[i + 1]; | ||
+ }else if (!strcmp(PARAM_PIPE_1_READ, argv[i])){ | ||
+ char* p1r = argv[i + 1]; | ||
+ pipe_fd1[0] = atoi(p1r); | ||
+ }else if (!strcmp(PARAM_PIPE_1_WRITE, argv[i])) { | ||
+ char* p1w = argv[i + 1]; | ||
+ pipe_fd1[1] = atoi(p1w); | ||
+ }else if (!strcmp(PARAM_PIPE_2_READ, argv[i])) { | ||
+ char* p2r = argv[i + 1]; | ||
+ pipe_fd2[0] = atoi(p2r); | ||
+ }else if (!strcmp(PARAM_PIPE_2_WRITE, argv[i])) { | ||
+ char* p2w = argv[i + 1]; | ||
+ pipe_fd2[1] = atoi(p2w); | ||
+ } | ||
+ } | ||
+ | ||
+ close(pipe_fd1[0]); | ||
+ close(pipe_fd2[1]); | ||
+ | ||
+ char r_buf[100]; | ||
+ int r_num; | ||
+ memset(r_buf,0, sizeof(r_buf)); | ||
+ | ||
+ r_num=read(pipe_fd2[0], r_buf, 100); | ||
+ LOGE("Watch >>>>PARENT<<<< Dead !!"); | ||
+ int count = 0; | ||
+ while(count < 50){ | ||
+ start_service(pkg_name, svc_name); | ||
+ usleep(100000); | ||
+ count++; | ||
+ } | ||
+ }else{ | ||
+ exit(EXIT_SUCCESS); | ||
+ } | ||
+} |
145
LibMarsdaemon/jni/daemon_api20.c
@@ -0,0 +1,145 @@ | ||
+/* | ||
+ * File : daemon_api21.c | ||
+ * Author : Mars Kwok | ||
+ * Date : Jul. 21, 2015 | ||
+ * Description : This is used to watch process dead under api 20 | ||
+ * | ||
+ * Copyright (C) Mars Kwok<Marswin89@gmail.com> | ||
+ * | ||
+ */ | ||
+#include <stdio.h> | ||
+#include <dirent.h> | ||
+#include <unistd.h> | ||
+ | ||
+#include "log.h" | ||
+#include "constant.h" | ||
+#include "com_marswin89_marsdaemon_nativ_NativeDaemonAPI20.h" | ||
+ | ||
+ | ||
+ | ||
+/** | ||
+ * get the process pid by process name | ||
+ */ | ||
+int find_pid_by_name(char *pid_name, int *pid_list){ | ||
+ DIR *dir; | ||
+ struct dirent *next; | ||
+ int i = 0; | ||
+ pid_list[0] = 0; | ||
+ dir = opendir("/proc"); | ||
+ if (!dir){ | ||
+ return 0; | ||
+ } | ||
+ while ((next = readdir(dir)) != NULL){ | ||
+ FILE *status; | ||
+ char proc_file_name[BUFFER_SIZE]; | ||
+ char buffer[BUFFER_SIZE]; | ||
+ char process_name[BUFFER_SIZE]; | ||
+ | ||
+ if (strcmp(next->d_name, "..") == 0){ | ||
+ continue; | ||
+ } | ||
+ if (!isdigit(*next->d_name)){ | ||
+ continue; | ||
+ } | ||
+ sprintf(proc_file_name, "/proc/%s/cmdline", next->d_name); | ||
+ if (!(status = fopen(proc_file_name, "r"))){ | ||
+ continue; | ||
+ } | ||
+ if (fgets(buffer, BUFFER_SIZE - 1, status) == NULL){ | ||
+ fclose(status); | ||
+ continue; | ||
+ } | ||
+ fclose(status); | ||
+ sscanf(buffer, "%[^-]", process_name); | ||
+ if (strcmp(process_name, pid_name) == 0){ | ||
+ pid_list[i ++] = atoi(next->d_name); | ||
+ } | ||
+ } | ||
+ if (pid_list){ | ||
+ pid_list[i] = 0; | ||
+ } | ||
+ closedir(dir); | ||
+ return i; | ||
+} | ||
+ | ||
+/** | ||
+ * kill all process by name | ||
+ */ | ||
+void kill_zombie_process(char* zombie_name){ | ||
+ int pid_list[200]; | ||
+ int total_num = find_pid_by_name(zombie_name, pid_list); | ||
+ LOGD("zombie process name is %s, and number is %d, killing...", zombie_name, total_num); | ||
+ int i; | ||
+ for (i = 0; i < total_num; i ++) { | ||
+ int retval = 0; | ||
+ int daemon_pid = pid_list[i]; | ||
+ if (daemon_pid > 1 && daemon_pid != getpid() && daemon_pid != getppid()){ | ||
+ retval = kill(daemon_pid, SIGTERM); | ||
+ if (!retval){ | ||
+ LOGD("kill zombie successfully, zombie`s pid = %d", daemon_pid); | ||
+ }else{ | ||
+ LOGE("kill zombie failed, zombie`s pid = %d", daemon_pid); | ||
+ } | ||
+ } | ||
+ } | ||
+} | ||
+ | ||
+JNIEXPORT void JNICALL Java_com_marswin89_marsdaemon_nativ_NativeDaemonAPI20_doDaemon(JNIEnv *env, jobject jobj, jstring pkgName, jstring svcName, jstring daemonPath){ | ||
+ if(pkgName == NULL || svcName == NULL || daemonPath == NULL){ | ||
+ LOGE("native doDaemon parameters cannot be NULL !"); | ||
+ return ; | ||
+ } | ||
+ | ||
+ char *pkg_name = (char*)(*env)->GetStringUTFChars(env, pkgName, 0); | ||
+ char *svc_name = (char*)(*env)->GetStringUTFChars(env, svcName, 0); | ||
+ char *daemon_path = (char*)(*env)->GetStringUTFChars(env, daemonPath, 0); | ||
+ | ||
+ kill_zombie_process(NATIVE_DAEMON_NAME); | ||
+ | ||
+ int pipe_fd1[2];//order to watch child | ||
+ int pipe_fd2[2];//order to watch parent | ||
+ | ||
+ pid_t pid; | ||
+ char r_buf[100]; | ||
+ int r_num; | ||
+ memset(r_buf, 0, sizeof(r_buf)); | ||
+ if(pipe(pipe_fd1)<0){ | ||
+ LOGE("pipe1 create error"); | ||
+ return ; | ||
+ } | ||
+ if(pipe(pipe_fd2)<0){ | ||
+ LOGE("pipe2 create error"); | ||
+ return ; | ||
+ } | ||
+ | ||
+ char str_p1r[10]; | ||
+ char str_p1w[10]; | ||
+ char str_p2r[10]; | ||
+ char str_p2w[10]; | ||
+ | ||
+ sprintf(str_p1r,"%d",pipe_fd1[0]); | ||
+ sprintf(str_p1w,"%d",pipe_fd1[1]); | ||
+ sprintf(str_p2r,"%d",pipe_fd2[0]); | ||
+ sprintf(str_p2w,"%d",pipe_fd2[1]); | ||
+ | ||
+ | ||
+ if((pid=fork())==0){ | ||
+ execlp(daemon_path, | ||
+ NATIVE_DAEMON_NAME, | ||
+ PARAM_PKG_NAME, pkg_name, | ||
+ PARAM_SVC_NAME, svc_name, | ||
+ PARAM_PIPE_1_READ, str_p1r, | ||
+ PARAM_PIPE_1_WRITE, str_p1w, | ||
+ PARAM_PIPE_2_READ, str_p2r, | ||
+ PARAM_PIPE_2_WRITE, str_p2w, | ||
+ (char *) NULL); | ||
+ }else if(pid>0){ | ||
+ close(pipe_fd1[1]); | ||
+ close(pipe_fd2[0]); | ||
+ //wait for child | ||
+ r_num=read(pipe_fd1[0], r_buf, 100); | ||
+ LOGE("Watch >>>>CHILD<<<< Dead !!!"); | ||
+ java_callback(env, jobj, DAEMON_CALLBACK_NAME); | ||
+ } | ||
+} | ||
+ |
144
LibMarsdaemon/jni/daemon_api21.c
@@ -0,0 +1,144 @@ | ||
+/* | ||
+ * File : daemon_api21.c | ||
+ * Author : Mars Kwok | ||
+ * Date : Jul. 21, 2015 | ||
+ * Description : This is used to watch process dead over api 21 | ||
+ * | ||
+ * Copyright (C) Mars Kwok<Marswin89@gmail.com> | ||
+ * | ||
+ */ | ||
+#include <fcntl.h> | ||
+#include <sys/stat.h> | ||
+#include <sys/inotify.h> | ||
+ | ||
+#include "com_marswin89_marsdaemon_nativ_NativeDaemonAPI21.h" | ||
+#include "log.h" | ||
+#include "constant.h" | ||
+ | ||
+void waitfor_self_observer(char* observer_file_path){ | ||
+ int lockFileDescriptor = open(observer_file_path, O_RDONLY); | ||
+ if (lockFileDescriptor == -1){ | ||
+ LOGE("Watched >>>>OBSERVER<<<< has been ready before watching..."); | ||
+ return ; | ||
+ } | ||
+ | ||
+ void *p_buf = malloc(sizeof(struct inotify_event)); | ||
+ if (p_buf == NULL){ | ||
+ LOGE("malloc failed !!!"); | ||
+ return; | ||
+ } | ||
+ int maskStrLength = 7 + 10 + 1; | ||
+ char *p_maskStr = malloc(maskStrLength); | ||
+ if (p_maskStr == NULL){ | ||
+ free(p_buf); | ||
+ LOGE("malloc failed !!!"); | ||
+ return; | ||
+ } | ||
+ int fileDescriptor = inotify_init(); | ||
+ if (fileDescriptor < 0){ | ||
+ free(p_buf); | ||
+ free(p_maskStr); | ||
+ LOGE("inotify_init failed !!!"); | ||
+ return; | ||
+ } | ||
+ | ||
+ int watchDescriptor = inotify_add_watch(fileDescriptor, observer_file_path, IN_ALL_EVENTS); | ||
+ if (watchDescriptor < 0){ | ||
+ free(p_buf); | ||
+ free(p_maskStr); | ||
+ LOGE("inotify_add_watch failed !!!"); | ||
+ return; | ||
+ } | ||
+ | ||
+ | ||
+ while(1){ | ||
+ size_t readBytes = read(fileDescriptor, p_buf, sizeof(struct inotify_event)); | ||
+ if (4 == ((struct inotify_event *) p_buf)->mask){ | ||
+ LOGE("Watched >>>>OBSERVER<<<< has been ready..."); | ||
+ free(p_maskStr); | ||
+ free(p_buf); | ||
+ return; | ||
+ } | ||
+ } | ||
+} | ||
+ | ||
+void notify_daemon_observer(unsigned char is_persistent, char* observer_file_path){ | ||
+ if(!is_persistent){ | ||
+ int lockFileDescriptor = open(observer_file_path, O_RDONLY); | ||
+ while(lockFileDescriptor == -1){ | ||
+ lockFileDescriptor = open(observer_file_path, O_RDONLY); | ||
+ } | ||
+ } | ||
+ remove(observer_file_path); | ||
+} | ||
+ | ||
+notify_and_waitfor(char *observer_self_path, char *observer_daemon_path){ | ||
+ int observer_self_descriptor = open(observer_self_path, O_RDONLY); | ||
+ if (observer_self_descriptor == -1){ | ||
+ observer_self_descriptor = open(observer_self_path, O_CREAT, S_IRUSR | S_IWUSR); | ||
+ } | ||
+ int observer_daemon_descriptor = open(observer_daemon_path, O_RDONLY); | ||
+ while (observer_daemon_descriptor == -1){ | ||
+ usleep(1000); | ||
+ observer_daemon_descriptor = open(observer_daemon_path, O_RDONLY); | ||
+ } | ||
+ remove(observer_daemon_path); | ||
+ LOGE("Watched >>>>OBSERVER<<<< has been ready..."); | ||
+} | ||
+ | ||
+ | ||
+/** | ||
+ * Lock the file, this is block method. | ||
+ */ | ||
+int lock_file(char* lock_file_path){ | ||
+ LOGD("start try to lock file >> %s <<", lock_file_path); | ||
+ int lockFileDescriptor = open(lock_file_path, O_RDONLY); | ||
+ if (lockFileDescriptor == -1){ | ||
+ lockFileDescriptor = open(lock_file_path, O_CREAT, S_IRUSR); | ||
+ } | ||
+ int lockRet = flock(lockFileDescriptor, LOCK_EX); | ||
+ if (lockRet == -1){ | ||
+ LOGE("lock file failed >> %s <<", lock_file_path); | ||
+ return 0; | ||
+ }else{ | ||
+ LOGD("lock file success >> %s <<", lock_file_path); | ||
+ return 1; | ||
+ } | ||
+} | ||
+ | ||
+ | ||
+JNIEXPORT void JNICALL Java_com_marswin89_marsdaemon_nativ_NativeDaemonAPI21_doDaemon(JNIEnv *env, jobject jobj, jstring indicatorSelfPath, jstring indicatorDaemonPath, jstring observerSelfPath, jstring observerDaemonPath){ | ||
+ if(indicatorSelfPath == NULL || indicatorDaemonPath == NULL || observerSelfPath == NULL || observerDaemonPath == NULL){ | ||
+ LOGE("parameters cannot be NULL !"); | ||
+ return ; | ||
+ } | ||
+ | ||
+ char* indicator_self_path = (char*)(*env)->GetStringUTFChars(env, indicatorSelfPath, 0); | ||
+ char* indicator_daemon_path = (char*)(*env)->GetStringUTFChars(env, indicatorDaemonPath, 0); | ||
+ char* observer_self_path = (char*)(*env)->GetStringUTFChars(env, observerSelfPath, 0); | ||
+ char* observer_daemon_path = (char*)(*env)->GetStringUTFChars(env, observerDaemonPath, 0); | ||
+ | ||
+ int lock_status = 0; | ||
+ int try_time = 0; | ||
+ while(try_time < 3 && !(lock_status = lock_file(indicator_self_path))){ | ||
+ try_time++; | ||
+ LOGD("Persistent lock myself failed and try again as %d times", try_time); | ||
+ usleep(10000); | ||
+ } | ||
+ if(!lock_status){ | ||
+ LOGE("Persistent lock myself failed and exit"); | ||
+ return ; | ||
+ } | ||
+ | ||
+// notify_daemon_observer(observer_daemon_path); | ||
+// waitfor_self_observer(observer_self_path); | ||
+ notify_and_waitfor(observer_self_path, observer_daemon_path); | ||
+ | ||
+ lock_status = lock_file(indicator_daemon_path); | ||
+ if(lock_status){ | ||
+ LOGE("Watch >>>>DAEMON<<<<< Daed !!"); | ||
+ remove(observer_self_path);// it`s important ! to prevent from deadlock | ||
+ java_callback(env, jobj, DAEMON_CALLBACK_NAME); | ||
+ } | ||
+ | ||
+} |
16
LibMarsdaemon/jni/log.h
@@ -0,0 +1,16 @@ | ||
+/* | ||
+ * File : daemon_below20.c | ||
+ * Author : Guoyang3 | ||
+ * Date : Aug. 14, 2015 | ||
+ * Description : for easy log. | ||
+ */ | ||
+ | ||
+#include <jni.h> | ||
+#include <android/log.h> | ||
+ | ||
+#define TAG "Daemon" | ||
+ | ||
+#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, TAG, __VA_ARGS__) | ||
+#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, TAG, __VA_ARGS__) | ||
+#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, TAG, __VA_ARGS__) | ||
+#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, TAG, __VA_ARGS__) |
BIN
LibMarsdaemon/libs/armeabi-v7a/libdaemon_api20.so
Binary file not shown.
BIN
LibMarsdaemon/libs/armeabi-v7a/libdaemon_api21.so
Binary file not shown.
BIN
LibMarsdaemon/libs/armeabi/libdaemon_api20.so
Binary file not shown.
BIN
LibMarsdaemon/libs/armeabi/libdaemon_api21.so
Binary file not shown.
BIN
LibMarsdaemon/libs/x86/libdaemon_api20.so
Binary file not shown.
BIN
LibMarsdaemon/libs/x86/libdaemon_api21.so
Binary file not shown.
26
LibMarsdaemon/proguard-rules.pro
@@ -0,0 +1,26 @@ | ||
+# Add project specific ProGuard rules here. | ||
+# By default, the flags in this file are appended to flags specified | ||
+# in /Users/guoyang/Developer/android-sdk-macosx/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 *; | ||
+#} | ||
+ | ||
+-keep class com.marswin89.marsdaemon.NativeDaemonBase{*;} | ||
+-keep class com.marswin89.marsdaemon.nativ.NativeDaemonAPI20{*;} | ||
+-keep class com.marswin89.marsdaemon.nativ.NativeDaemonAPI21{*;} | ||
+-keep class com.marswin89.marsdaemon.DaemonApplication{*;} | ||
+-keep class com.marswin89.marsdaemon.DaemonClient{*;} | ||
+-keepattributes Exceptions,InnerClasses,... | ||
+-keep class com.marswin89.marsdaemon.DaemonConfigurations{*;} | ||
+-keep class com.marswin89.marsdaemon.DaemonConfigurations$*{*;} |
11
LibMarsdaemon/src/main/AndroidManifest.xml
@@ -0,0 +1,11 @@ | ||
+<manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||
+ package="com.marswin89.marsdaemon"> | ||
+ | ||
+ <application | ||
+ android:allowBackup="true" | ||
+ android:label="@string/app_name" | ||
+ android:supportsRtl="true"> | ||
+ | ||
+ </application> | ||
+ | ||
+</manifest> |
BIN
LibMarsdaemon/src/main/assets/armeabi-v7a/daemon
Binary file not shown.
BIN
LibMarsdaemon/src/main/assets/armeabi/daemon
Binary file not shown.
BIN
LibMarsdaemon/src/main/assets/x86/daemon
Binary file not shown.
54
LibMarsdaemon/src/main/java/com/marswin89/marsdaemon/DaemonApplication.java
@@ -0,0 +1,54 @@ | ||
+package com.marswin89.marsdaemon; | ||
+ | ||
+import android.app.Application; | ||
+import android.content.Context; | ||
+ | ||
+/** | ||
+ * make your Application extends it | ||
+ * @author Mars | ||
+ * | ||
+ */ | ||
+public abstract class DaemonApplication extends Application{ | ||
+ /** | ||
+ * Daemon SDK needs the Daemon Configurations contains two process informations</br> | ||
+ * see {@link DaemonConfigurations} and {@link DaemonConfigurations.DaemonConfiguration} | ||
+ * | ||
+ * @return DaemonConfigurations | ||
+ */ | ||
+ protected abstract DaemonConfigurations getDaemonConfigurations(); | ||
+ | ||
+ | ||
+ | ||
+ private IDaemonClient mDaemonClient; | ||
+ public DaemonApplication(){ | ||
+ mDaemonClient = new DaemonClient(getDaemonConfigurations()); | ||
+ } | ||
+ | ||
+ | ||
+ /** | ||
+ * order to prevent performing super.attachBaseContext() by child class</br> | ||
+ * if do it, it will cause the IllegalStateException if a base context has already been set. | ||
+ */ | ||
+ private boolean mHasAttachBaseContext = false; | ||
+ | ||
+ @Override | ||
+ public final void attachBaseContext(Context base) { | ||
+ if(mHasAttachBaseContext){ | ||
+ return ; | ||
+ } | ||
+ mHasAttachBaseContext = true; | ||
+ super.attachBaseContext(base); | ||
+ mDaemonClient.onAttachBaseContext(base); | ||
+ attachBaseContextByDaemon(base); | ||
+ } | ||
+ | ||
+ /** | ||
+ * instead of {{@link #attachBaseContext(Context)}, you can override this.</br> | ||
+ * @param base | ||
+ */ | ||
+ public void attachBaseContextByDaemon(Context base){ | ||
+ | ||
+ } | ||
+ | ||
+ | ||
+} |
110
LibMarsdaemon/src/main/java/com/marswin89/marsdaemon/DaemonClient.java
@@ -0,0 +1,110 @@ | ||
+package com.marswin89.marsdaemon; | ||
+ | ||
+import java.io.BufferedReader; | ||
+import java.io.File; | ||
+import java.io.FileReader; | ||
+import java.io.IOException; | ||
+ | ||
+import android.content.Context; | ||
+import android.content.SharedPreferences; | ||
+import android.content.SharedPreferences.Editor; | ||
+ | ||
+/** | ||
+ * | ||
+ * @author Mars | ||
+ * | ||
+ */ | ||
+public class DaemonClient implements IDaemonClient{ | ||
+ private DaemonConfigurations mConfigurations; | ||
+ public DaemonClient(DaemonConfigurations configurations) { | ||
+ this.mConfigurations = configurations; | ||
+ } | ||
+ @Override | ||
+ public void onAttachBaseContext(Context base) { | ||
+ initDaemon(base); | ||
+ } | ||
+ | ||
+ | ||
+ private final String DAEMON_PERMITTING_SP_FILENAME = "d_permit"; | ||
+ private final String DAEMON_PERMITTING_SP_KEY = "permitted"; | ||
+ | ||
+ | ||
+ private BufferedReader mBufferedReader;//release later to save time | ||
+ | ||
+ | ||
+ /** | ||
+ * do some thing about daemon | ||
+ * @param base | ||
+ */ | ||
+ private void initDaemon(Context base) { | ||
+ if(!isDaemonPermitting(base) || mConfigurations == null){ | ||
+ return ; | ||
+ } | ||
+ String processName = getProcessName(); | ||
+ String packageName = base.getPackageName(); | ||
+ | ||
+ if(processName.startsWith(mConfigurations.PERSISTENT_CONFIG.PROCESS_NAME)){ | ||
+ IDaemonStrategy.Fetcher.fetchStrategy().onPersistentCreate(base, mConfigurations); | ||
+ }else if(processName.startsWith(mConfigurations.DAEMON_ASSISTANT_CONFIG.PROCESS_NAME)){ | ||
+ IDaemonStrategy.Fetcher.fetchStrategy().onDaemonAssistantCreate(base, mConfigurations); | ||
+ }else if(processName.startsWith(packageName)){ | ||
+ IDaemonStrategy.Fetcher.fetchStrategy().onInitialization(base); | ||
+ } | ||
+ | ||
+ releaseIO(); | ||
+ } | ||
+ | ||
+ | ||
+ /* spend too much time !! 60+ms | ||
+ private String getProcessName(){ | ||
+ ActivityManager am = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE); | ||
+ int pid = android.os.Process.myPid(); | ||
+ List<RunningAppProcessInfo> infos = am.getRunningAppProcesses(); | ||
+ for (int i = 0; i < infos.size(); i++) { | ||
+ RunningAppProcessInfo info = infos.get(i); | ||
+ if(pid == info.pid){ | ||
+ return info.processName; | ||
+ } | ||
+ } | ||
+ return null; | ||
+ } | ||
+ */ | ||
+ | ||
+ private String getProcessName() { | ||
+ try { | ||
+ File file = new File("/proc/" + android.os.Process.myPid() + "/" + "cmdline"); | ||
+ mBufferedReader = new BufferedReader(new FileReader(file)); | ||
+ return mBufferedReader.readLine(); | ||
+ } catch (Exception e) { | ||
+ e.printStackTrace(); | ||
+ return null; | ||
+ } | ||
+ } | ||
+ | ||
+ /** | ||
+ * release reader IO | ||
+ */ | ||
+ private void releaseIO(){ | ||
+ if(mBufferedReader != null){ | ||
+ try { | ||
+ mBufferedReader.close(); | ||
+ } catch (IOException e) { | ||
+ e.printStackTrace(); | ||
+ } | ||
+ mBufferedReader = null; | ||
+ } | ||
+ } | ||
+ | ||
+ private boolean isDaemonPermitting(Context context){ | ||
+ SharedPreferences sp = context.getSharedPreferences(DAEMON_PERMITTING_SP_FILENAME, Context.MODE_PRIVATE); | ||
+ return sp.getBoolean(DAEMON_PERMITTING_SP_KEY, true); | ||
+ } | ||
+ | ||
+ protected boolean setDaemonPermiiting(Context context, boolean isPermitting) { | ||
+ SharedPreferences sp = context.getSharedPreferences(DAEMON_PERMITTING_SP_FILENAME, Context.MODE_PRIVATE); | ||
+ Editor editor = sp.edit(); | ||
+ editor.putBoolean(DAEMON_PERMITTING_SP_KEY, isPermitting); | ||
+ return editor.commit(); | ||
+ } | ||
+ | ||
+} |
59
LibMarsdaemon/src/main/java/com/marswin89/marsdaemon/DaemonConfigurations.java
@@ -0,0 +1,59 @@ | ||
+package com.marswin89.marsdaemon; | ||
+ | ||
+import android.content.Context; | ||
+ | ||
+/** | ||
+ * the configurations of Daemon SDK, contains two process configuration. | ||
+ * @author Mars | ||
+ * | ||
+ */ | ||
+public class DaemonConfigurations { | ||
+ | ||
+ public final DaemonConfiguration PERSISTENT_CONFIG; | ||
+ public final DaemonConfiguration DAEMON_ASSISTANT_CONFIG; | ||
+ public final DaemonListener LISTENER; | ||
+ | ||
+ public DaemonConfigurations(DaemonConfiguration persistentConfig, DaemonConfiguration daemonAssistantConfig){ | ||
+ this.PERSISTENT_CONFIG = persistentConfig; | ||
+ this.DAEMON_ASSISTANT_CONFIG = daemonAssistantConfig; | ||
+ this.LISTENER = null; | ||
+ } | ||
+ | ||
+ public DaemonConfigurations(DaemonConfiguration persistentConfig, DaemonConfiguration daemonAssistantConfig, DaemonListener listener){ | ||
+ this.PERSISTENT_CONFIG = persistentConfig; | ||
+ this.DAEMON_ASSISTANT_CONFIG = daemonAssistantConfig; | ||
+ this.LISTENER = listener; | ||
+ } | ||
+ | ||
+ | ||
+ | ||
+ /** | ||
+ * the configuration of a daemon process, contains process name, service name and receiver name if Android 6.0 | ||
+ * @author guoyang | ||
+ * | ||
+ */ | ||
+ public static class DaemonConfiguration{ | ||
+ | ||
+ public final String PROCESS_NAME; | ||
+ public final String SERVICE_NAME; | ||
+ public final String RECEIVER_NAME; | ||
+ | ||
+ public DaemonConfiguration(String processName, String serviceName, String receiverName){ | ||
+ this.PROCESS_NAME = processName; | ||
+ this.SERVICE_NAME = serviceName; | ||
+ this.RECEIVER_NAME = receiverName; | ||
+ } | ||
+ } | ||
+ | ||
+ /** | ||
+ * listener of daemon for external | ||
+ * | ||
+ * @author Mars | ||
+ * | ||
+ */ | ||
+ public interface DaemonListener { | ||
+ void onPersistentStart(Context context); | ||
+ void onDaemonAssistantStart(Context context); | ||
+ void onWatchDaemonDaed(); | ||
+ } | ||
+} |
20
LibMarsdaemon/src/main/java/com/marswin89/marsdaemon/IDaemonClient.java
@@ -0,0 +1,20 @@ | ||
+package com.marswin89.marsdaemon; | ||
+ | ||
+import android.content.Context; | ||
+ | ||
+/** | ||
+ * | ||
+ * @author Mars | ||
+ * | ||
+ */ | ||
+public interface IDaemonClient { | ||
+ /** | ||
+ * override this method by {@link android.app.Application}</br></br> | ||
+ * ****************************************************************</br> | ||
+ * <b>DO super.attchBaseContext() first !</b></br> | ||
+ * ****************************************************************</br> | ||
+ * | ||
+ * @param base | ||
+ */ | ||
+ void onAttachBaseContext(Context base); | ||
+} |
97
LibMarsdaemon/src/main/java/com/marswin89/marsdaemon/IDaemonStrategy.java
@@ -0,0 +1,97 @@ | ||
+package com.marswin89.marsdaemon; | ||
+ | ||
+import com.marswin89.marsdaemon.strategy.DaemonStrategy21; | ||
+import com.marswin89.marsdaemon.strategy.DaemonStrategy22; | ||
+import com.marswin89.marsdaemon.strategy.DaemonStrategy23; | ||
+import com.marswin89.marsdaemon.strategy.DaemonStrategyUnder21; | ||
+import com.marswin89.marsdaemon.strategy.DaemonStrategyXiaomi; | ||
+ | ||
+import android.content.Context; | ||
+import android.os.Build; | ||
+ | ||
+/** | ||
+ * define strategy method | ||
+ * | ||
+ * @author Mars | ||
+ * | ||
+ */ | ||
+public interface IDaemonStrategy { | ||
+ /** | ||
+ * Initialization some files or other when 1st time | ||
+ * | ||
+ * @param context | ||
+ * @return | ||
+ */ | ||
+ boolean onInitialization(Context context); | ||
+ | ||
+ /** | ||
+ * when Persistent process create | ||
+ * | ||
+ * @param context | ||
+ * @param configs | ||
+ */ | ||
+ void onPersistentCreate(Context context, DaemonConfigurations configs); | ||
+ | ||
+ /** | ||
+ * when DaemonAssistant process create | ||
+ * @param context | ||
+ * @param configs | ||
+ */ | ||
+ void onDaemonAssistantCreate(Context context, DaemonConfigurations configs); | ||
+ | ||
+ /** | ||
+ * when watches the process dead which it watched | ||
+ */ | ||
+ void onDaemonDead(); | ||
+ | ||
+ | ||
+ | ||
+ /** | ||
+ * all about strategy on different device here | ||
+ * | ||
+ * @author Mars | ||
+ * | ||
+ */ | ||
+ public static class Fetcher { | ||
+ | ||
+ private static IDaemonStrategy mDaemonStrategy; | ||
+ | ||
+ /** | ||
+ * fetch the strategy for this device | ||
+ * | ||
+ * @return the daemon strategy for this device | ||
+ */ | ||
+ static IDaemonStrategy fetchStrategy() { | ||
+ if (mDaemonStrategy != null) { | ||
+ return mDaemonStrategy; | ||
+ } | ||
+ int sdk = Build.VERSION.SDK_INT; | ||
+ switch (sdk) { | ||
+ case 23: | ||
+ mDaemonStrategy = new DaemonStrategy23(); | ||
+ break; | ||
+ | ||
+ case 22: | ||
+ mDaemonStrategy = new DaemonStrategy22(); | ||
+ break; | ||
+ | ||
+ case 21: | ||
+ if("MX4 Pro".equalsIgnoreCase(Build.MODEL)){ | ||
+ mDaemonStrategy = new DaemonStrategyUnder21(); | ||
+ }else{ | ||
+ mDaemonStrategy = new DaemonStrategy21(); | ||
+ } | ||
+ break; | ||
+ | ||
+ default: | ||
+ if(Build.MODEL != null && Build.MODEL.toLowerCase().startsWith("mi")){ | ||
+ mDaemonStrategy = new DaemonStrategyXiaomi(); | ||
+ }else{ | ||
+ mDaemonStrategy = new DaemonStrategyUnder21(); | ||
+ } | ||
+ break; | ||
+ } | ||
+ return mDaemonStrategy; | ||
+ } | ||
+ } | ||
+} |
28
LibMarsdaemon/src/main/java/com/marswin89/marsdaemon/NativeDaemonBase.java
@@ -0,0 +1,28 @@ | ||
+package com.marswin89.marsdaemon; | ||
+ | ||
+import android.content.Context; | ||
+ | ||
+/** | ||
+ * native base class | ||
+ * | ||
+ * @author Mars | ||
+ * | ||
+ */ | ||
+public class NativeDaemonBase { | ||
+ /** | ||
+ * used for native | ||
+ */ | ||
+ protected Context mContext; | ||
+ | ||
+ public NativeDaemonBase(Context context){ | ||
+ this.mContext = context; | ||
+ } | ||
+ | ||
+ /** | ||
+ * native call back | ||
+ */ | ||
+ protected void onDaemonDead(){ | ||
+ IDaemonStrategy.Fetcher.fetchStrategy().onDaemonDead(); | ||
+ } | ||
+ | ||
+} |
35
LibMarsdaemon/src/main/java/com/marswin89/marsdaemon/PackageUtils.java
@@ -0,0 +1,35 @@ | ||
+package com.marswin89.marsdaemon; | ||
+ | ||
+import android.content.ComponentName; | ||
+import android.content.Context; | ||
+import android.content.pm.PackageManager; | ||
+ | ||
+/** | ||
+ * Utils to prevent component from third-party app forbidding | ||
+ * | ||
+ * @author Mars | ||
+ * | ||
+ */ | ||
+public class PackageUtils { | ||
+ /** | ||
+ * set the component in our package default | ||
+ * @param context | ||
+ * @param componentClassName | ||
+ */ | ||
+ public static void setComponentDefault(Context context, String componentClassName){ | ||
+ PackageManager pm = context.getPackageManager(); | ||
+ ComponentName componentName = new ComponentName(context.getPackageName(), componentClassName); | ||
+ pm.setComponentEnabledSetting(componentName, PackageManager.COMPONENT_ENABLED_STATE_DEFAULT, PackageManager.DONT_KILL_APP); | ||
+ } | ||
+ | ||
+ /** | ||
+ * get the component in our package default | ||
+ * @param context | ||
+ * @param componentClassName | ||
+ */ | ||
+ public static boolean isComponentDefault(Context context, String componentClassName){ | ||
+ PackageManager pm = context.getPackageManager(); | ||
+ ComponentName componentName = new ComponentName(context.getPackageName(), componentClassName); | ||
+ return pm.getComponentEnabledSetting(componentName) == PackageManager.COMPONENT_ENABLED_STATE_DEFAULT; | ||
+ } | ||
+} |
28
LibMarsdaemon/src/main/java/com/marswin89/marsdaemon/nativ/NativeDaemonAPI20.java
@@ -0,0 +1,28 @@ | ||
+package com.marswin89.marsdaemon.nativ; | ||
+ | ||
+import com.marswin89.marsdaemon.NativeDaemonBase; | ||
+ | ||
+import android.content.Context; | ||
+ | ||
+/** | ||
+ * native code to watch each other when api under 20 (contains 20) | ||
+ * @author Mars | ||
+ * | ||
+ */ | ||
+public class NativeDaemonAPI20 extends NativeDaemonBase { | ||
+ | ||
+ public NativeDaemonAPI20(Context context) { | ||
+ super(context); | ||
+ } | ||
+ | ||
+ static{ | ||
+ try { | ||
+ System.loadLibrary("daemon_api20"); | ||
+ } catch (Exception e) { | ||
+ e.printStackTrace(); | ||
+ } | ||
+ } | ||
+ | ||
+ public native void doDaemon(String pkgName, String svcName, String daemonPath); | ||
+ | ||
+} |
27
LibMarsdaemon/src/main/java/com/marswin89/marsdaemon/nativ/NativeDaemonAPI21.java
@@ -0,0 +1,27 @@ | ||
+package com.marswin89.marsdaemon.nativ; | ||
+ | ||
+import com.marswin89.marsdaemon.NativeDaemonBase; | ||
+ | ||
+import android.content.Context; | ||
+ | ||
+/** | ||
+ * native code to watch each other when api over 21 (contains 21) | ||
+ * @author Mars | ||
+ * | ||
+ */ | ||
+public class NativeDaemonAPI21 extends NativeDaemonBase{ | ||
+ | ||
+ public NativeDaemonAPI21(Context context) { | ||
+ super(context); | ||
+ } | ||
+ | ||
+ static{ | ||
+ try { | ||
+ System.loadLibrary("daemon_api21"); | ||
+ } catch (Exception e) { | ||
+ e.printStackTrace(); | ||
+ } | ||
+ } | ||
+ | ||
+ public native void doDaemon(String indicatorSelfPath, String indicatorDaemonPath, String observerSelfPath, String observerDaemonPath); | ||
+} |
144
LibMarsdaemon/src/main/java/com/marswin89/marsdaemon/strategy/DaemonStrategy21.java
@@ -0,0 +1,144 @@ | ||
+package com.marswin89.marsdaemon.strategy; | ||
+ | ||
+import java.io.File; | ||
+import java.io.IOException; | ||
+ | ||
+import android.app.AlarmManager; | ||
+import android.app.PendingIntent; | ||
+import android.content.ComponentName; | ||
+import android.content.Context; | ||
+import android.content.Intent; | ||
+import android.os.SystemClock; | ||
+ | ||
+import com.marswin89.marsdaemon.DaemonConfigurations; | ||
+import com.marswin89.marsdaemon.IDaemonStrategy; | ||
+import com.marswin89.marsdaemon.nativ.NativeDaemonAPI21; | ||
+/** | ||
+ * the strategy in android API 21. | ||
+ * | ||
+ * @author Mars | ||
+ * | ||
+ */ | ||
+public class DaemonStrategy21 implements IDaemonStrategy{ | ||
+ private final static String INDICATOR_DIR_NAME = "indicators"; | ||
+ private final static String INDICATOR_PERSISTENT_FILENAME = "indicator_p"; | ||
+ private final static String INDICATOR_DAEMON_ASSISTANT_FILENAME = "indicator_d"; | ||
+ private final static String OBSERVER_PERSISTENT_FILENAME = "observer_p"; | ||
+ private final static String OBSERVER_DAEMON_ASSISTANT_FILENAME = "observer_d"; | ||
+ | ||
+ private AlarmManager mAlarmManager; | ||
+ private PendingIntent mPendingIntent; | ||
+ private DaemonConfigurations mConfigs; | ||
+ | ||
+ @Override | ||
+ public boolean onInitialization(Context context) { | ||
+ return initIndicators(context); | ||
+ } | ||
+ | ||
+ @Override | ||
+ public void onPersistentCreate(final Context context, DaemonConfigurations configs) { | ||
+ Intent intent = new Intent(); | ||
+ ComponentName componentName = new ComponentName(context.getPackageName(), configs.DAEMON_ASSISTANT_CONFIG.SERVICE_NAME); | ||
+ intent.setComponent(componentName); | ||
+ context.startService(intent); | ||
+ | ||
+ initAlarm(context, configs.PERSISTENT_CONFIG.SERVICE_NAME); | ||
+ | ||
+ Thread t = new Thread(){ | ||
+ @Override | ||
+ public void run() { | ||
+ File indicatorDir = context.getDir(INDICATOR_DIR_NAME, Context.MODE_PRIVATE); | ||
+ new NativeDaemonAPI21(context).doDaemon( | ||
+ new File(indicatorDir, INDICATOR_PERSISTENT_FILENAME).getAbsolutePath(), | ||
+ new File(indicatorDir, INDICATOR_DAEMON_ASSISTANT_FILENAME).getAbsolutePath(), | ||
+ new File(indicatorDir, OBSERVER_PERSISTENT_FILENAME).getAbsolutePath(), | ||
+ new File(indicatorDir, OBSERVER_DAEMON_ASSISTANT_FILENAME).getAbsolutePath()); | ||
+ } | ||
+ }; | ||
+ t.setPriority(Thread.MAX_PRIORITY); | ||
+ t.start(); | ||
+ | ||
+ if(configs != null && configs.LISTENER != null){ | ||
+ this.mConfigs = configs; | ||
+ configs.LISTENER.onPersistentStart(context); | ||
+ } | ||
+ } | ||
+ | ||
+ @Override | ||
+ public void onDaemonAssistantCreate(final Context context, DaemonConfigurations configs) { | ||
+ Intent intent = new Intent(); | ||
+ ComponentName componentName = new ComponentName(context.getPackageName(), configs.PERSISTENT_CONFIG.SERVICE_NAME); | ||
+ intent.setComponent(componentName); | ||
+ context.startService(intent); | ||
+ | ||
+ initAlarm(context, configs.PERSISTENT_CONFIG.SERVICE_NAME); | ||
+ | ||
+ Thread t = new Thread(){ | ||
+ public void run() { | ||
+ File indicatorDir = context.getDir(INDICATOR_DIR_NAME, Context.MODE_PRIVATE); | ||
+ new NativeDaemonAPI21(context).doDaemon( | ||
+ new File(indicatorDir, INDICATOR_DAEMON_ASSISTANT_FILENAME).getAbsolutePath(), | ||
+ new File(indicatorDir, INDICATOR_PERSISTENT_FILENAME).getAbsolutePath(), | ||
+ new File(indicatorDir, OBSERVER_DAEMON_ASSISTANT_FILENAME).getAbsolutePath(), | ||
+ new File(indicatorDir, OBSERVER_PERSISTENT_FILENAME).getAbsolutePath()); | ||
+ }; | ||
+ }; | ||
+ t.setPriority(Thread.MAX_PRIORITY); | ||
+ t.start(); | ||
+ | ||
+ if(configs != null && configs.LISTENER != null){ | ||
+ this.mConfigs = configs; | ||
+ configs.LISTENER.onDaemonAssistantStart(context); | ||
+ } | ||
+ } | ||
+ | ||
+ @Override | ||
+ public void onDaemonDead() { | ||
+ mAlarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime(), 100, mPendingIntent); | ||
+ | ||
+ if(mConfigs != null && mConfigs.LISTENER != null){ | ||
+ mConfigs.LISTENER.onWatchDaemonDaed(); | ||
+ } | ||
+ android.os.Process.killProcess(android.os.Process.myPid()); | ||
+ } | ||
+ | ||
+ | ||
+ private void initAlarm(Context context, String serviceName){ | ||
+ if(mAlarmManager == null){ | ||
+ mAlarmManager = ((AlarmManager)context.getSystemService(Context.ALARM_SERVICE)); | ||
+ } | ||
+ if(mPendingIntent == null){ | ||
+ Intent intent = new Intent(); | ||
+ ComponentName component = new ComponentName(context.getPackageName(), serviceName); | ||
+ intent.setComponent(component); | ||
+ intent.setFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES); | ||
+ mPendingIntent = PendingIntent.getService(context, 0, intent, 0); | ||
+ } | ||
+ mAlarmManager.cancel(mPendingIntent); | ||
+ } | ||
+ | ||
+ | ||
+ private boolean initIndicators(Context context){ | ||
+ File dirFile = context.getDir(INDICATOR_DIR_NAME, Context.MODE_PRIVATE); | ||
+ if(!dirFile.exists()){ | ||
+ dirFile.mkdirs(); | ||
+ } | ||
+ try { | ||
+ createNewFile(dirFile, INDICATOR_PERSISTENT_FILENAME); | ||
+ createNewFile(dirFile, INDICATOR_DAEMON_ASSISTANT_FILENAME); | ||
+ return true; | ||
+ } catch (IOException e) { | ||
+ e.printStackTrace(); | ||
+ return false; | ||
+ } | ||
+ } | ||
+ | ||
+ | ||
+ private void createNewFile(File dirFile, String fileName) throws IOException{ | ||
+ File file = new File(dirFile, fileName); | ||
+ if(!file.exists()){ | ||
+ file.createNewFile(); | ||
+ } | ||
+ } | ||
+ | ||
+} |
204
LibMarsdaemon/src/main/java/com/marswin89/marsdaemon/strategy/DaemonStrategy22.java
@@ -0,0 +1,204 @@ | ||
+package com.marswin89.marsdaemon.strategy; | ||
+ | ||
+import java.io.File; | ||
+import java.io.IOException; | ||
+import java.lang.reflect.Field; | ||
+import java.lang.reflect.InvocationTargetException; | ||
+ | ||
+import android.annotation.SuppressLint; | ||
+import android.content.ComponentName; | ||
+import android.content.Context; | ||
+import android.content.Intent; | ||
+import android.os.IBinder; | ||
+import android.os.Parcel; | ||
+import android.os.RemoteException; | ||
+import android.util.Log; | ||
+ | ||
+import com.marswin89.marsdaemon.DaemonConfigurations; | ||
+import com.marswin89.marsdaemon.IDaemonStrategy; | ||
+import com.marswin89.marsdaemon.nativ.NativeDaemonAPI21; | ||
+/** | ||
+ * the strategy in android API 22. | ||
+ * | ||
+ * @author Mars | ||
+ * | ||
+ */ | ||
+public class DaemonStrategy22 implements IDaemonStrategy{ | ||
+ private final static String INDICATOR_DIR_NAME = "indicators"; | ||
+ private final static String INDICATOR_PERSISTENT_FILENAME = "indicator_p"; | ||
+ private final static String INDICATOR_DAEMON_ASSISTANT_FILENAME = "indicator_d"; | ||
+ private final static String OBSERVER_PERSISTENT_FILENAME = "observer_p"; | ||
+ private final static String OBSERVER_DAEMON_ASSISTANT_FILENAME = "observer_d"; | ||
+ | ||
+ private IBinder mRemote; | ||
+ private Parcel mServiceData; | ||
+ private DaemonConfigurations mConfigs; | ||
+ | ||
+ @Override | ||
+ public boolean onInitialization(Context context) { | ||
+ return initIndicatorFiles(context); | ||
+ } | ||
+ | ||
+ @Override | ||
+ public void onPersistentCreate(final Context context, DaemonConfigurations configs) { | ||
+ initAmsBinder(); | ||
+ initServiceParcel(context, configs.DAEMON_ASSISTANT_CONFIG.SERVICE_NAME); | ||
+ startServiceByAmsBinder(); | ||
+ | ||
+ Thread t = new Thread(){ | ||
+ public void run() { | ||
+ File indicatorDir = context.getDir(INDICATOR_DIR_NAME, Context.MODE_PRIVATE); | ||
+ new NativeDaemonAPI21(context).doDaemon( | ||
+ new File(indicatorDir, INDICATOR_PERSISTENT_FILENAME).getAbsolutePath(), | ||
+ new File(indicatorDir, INDICATOR_DAEMON_ASSISTANT_FILENAME).getAbsolutePath(), | ||
+ new File(indicatorDir, OBSERVER_PERSISTENT_FILENAME).getAbsolutePath(), | ||
+ new File(indicatorDir, OBSERVER_DAEMON_ASSISTANT_FILENAME).getAbsolutePath()); | ||
+ }; | ||
+ }; | ||
+ t.start(); | ||
+ | ||
+ if(configs != null && configs.LISTENER != null){ | ||
+ this.mConfigs = configs; | ||
+ configs.LISTENER.onPersistentStart(context); | ||
+ } | ||
+ } | ||
+ | ||
+ @Override | ||
+ public void onDaemonAssistantCreate(final Context context, DaemonConfigurations configs) { | ||
+ initAmsBinder(); | ||
+ initServiceParcel(context, configs.PERSISTENT_CONFIG.SERVICE_NAME); | ||
+ startServiceByAmsBinder(); | ||
+ | ||
+ Thread t = new Thread(){ | ||
+ public void run() { | ||
+ File indicatorDir = context.getDir(INDICATOR_DIR_NAME, Context.MODE_PRIVATE); | ||
+ new NativeDaemonAPI21(context).doDaemon( | ||
+ new File(indicatorDir, INDICATOR_DAEMON_ASSISTANT_FILENAME).getAbsolutePath(), | ||
+ new File(indicatorDir, INDICATOR_PERSISTENT_FILENAME).getAbsolutePath(), | ||
+ new File(indicatorDir, OBSERVER_DAEMON_ASSISTANT_FILENAME).getAbsolutePath(), | ||
+ new File(indicatorDir, OBSERVER_PERSISTENT_FILENAME).getAbsolutePath()); | ||
+ }; | ||
+ }; | ||
+ t.start(); | ||
+ | ||
+ if(configs != null && configs.LISTENER != null){ | ||
+ this.mConfigs = configs; | ||
+ configs.LISTENER.onDaemonAssistantStart(context); | ||
+ } | ||
+ | ||
+ } | ||
+ | ||
+ | ||
+ @Override | ||
+ public void onDaemonDead() { | ||
+ if(startServiceByAmsBinder()){ | ||
+ | ||
+ if(mConfigs != null && mConfigs.LISTENER != null){ | ||
+ mConfigs.LISTENER.onWatchDaemonDaed(); | ||
+ } | ||
+ | ||
+ android.os.Process.killProcess(android.os.Process.myPid()); | ||
+ } | ||
+ } | ||
+ | ||
+ | ||
+ private void initAmsBinder(){ | ||
+ Class<?> activityManagerNative; | ||
+ try { | ||
+ activityManagerNative = Class.forName("android.app.ActivityManagerNative"); | ||
+ Object amn = activityManagerNative.getMethod("getDefault").invoke(activityManagerNative); | ||
+ Field mRemoteField = amn.getClass().getDeclaredField("mRemote"); | ||
+ mRemoteField.setAccessible(true); | ||
+ mRemote = (IBinder) mRemoteField.get(amn); | ||
+ } catch (ClassNotFoundException e) { | ||
+ e.printStackTrace(); | ||
+ } catch (IllegalAccessException e) { | ||
+ e.printStackTrace(); | ||
+ } catch (IllegalArgumentException e) { | ||
+ e.printStackTrace(); | ||
+ } catch (InvocationTargetException e) { | ||
+ e.printStackTrace(); | ||
+ } catch (NoSuchMethodException e) { | ||
+ e.printStackTrace(); | ||
+ } catch (NoSuchFieldException e) { | ||
+ e.printStackTrace(); | ||
+ } | ||
+ } | ||
+ | ||
+ | ||
+ @SuppressLint("Recycle")// when process dead, we should save time to restart and kill self, don`t take a waste of time to recycle | ||
+ private void initServiceParcel(Context context, String serviceName){ | ||
+ Intent intent = new Intent(); | ||
+ ComponentName component = new ComponentName(context.getPackageName(), serviceName); | ||
+ intent.setComponent(component); | ||
+ | ||
+ /* | ||
+ //get ContextImpl instance | ||
+// Object contextImpl = ((Application)context.getApplicationContext()).getBaseContext(); | ||
+ //this context is ContextImpl, get MainThread instance immediately | ||
+ Field mainThreadField = context.getClass().getDeclaredField("mMainThread"); | ||
+ mainThreadField.setAccessible(true); | ||
+ Object mainThread = mainThreadField.get(context); | ||
+ //get ApplicationThread instance | ||
+ Object applicationThread = mainThread.getClass().getMethod("getApplicationThread").invoke(mainThread); | ||
+ //get Binder | ||
+ Binder callerBinder = (Binder) (applicationThread.getClass().getMethod("asBinder").invoke(applicationThread)); | ||
+ */ | ||
+ | ||
+ //get handle | ||
+// UserHandle userHandle = android.os.Process.myUserHandle(); | ||
+// int handle = (Integer) userHandle.getClass().getMethod("getIdentifier").invoke(userHandle); | ||
+ | ||
+ //write pacel | ||
+ mServiceData = Parcel.obtain(); | ||
+ mServiceData.writeInterfaceToken("android.app.IActivityManager"); | ||
+ mServiceData.writeStrongBinder(null); | ||
+// mServiceData.writeStrongBinder(callerBinder); | ||
+ intent.writeToParcel(mServiceData, 0); | ||
+ mServiceData.writeString(null); | ||
+// mServiceData.writeString(intent.resolveTypeIfNeeded(context.getContentResolver())); | ||
+ mServiceData.writeInt(0); | ||
+// mServiceData.writeInt(handle); | ||
+ | ||
+ } | ||
+ | ||
+ | ||
+ private boolean startServiceByAmsBinder(){ | ||
+ try { | ||
+ if(mRemote == null || mServiceData == null){ | ||
+ Log.e("Daemon", "REMOTE IS NULL or PARCEL IS NULL !!!"); | ||
+ return false; | ||
+ } | ||
+ mRemote.transact(34, mServiceData, null, 0);//START_SERVICE_TRANSACTION = 34 | ||
+ return true; | ||
+ } catch (RemoteException e) { | ||
+ e.printStackTrace(); | ||
+ return false; | ||
+ } | ||
+ } | ||
+ | ||
+ | ||
+ | ||
+ | ||
+ private boolean initIndicatorFiles(Context context){ | ||
+ File dirFile = context.getDir(INDICATOR_DIR_NAME, Context.MODE_PRIVATE); | ||
+ if(!dirFile.exists()){ | ||
+ dirFile.mkdirs(); | ||
+ } | ||
+ try { | ||
+ createNewFile(dirFile, INDICATOR_PERSISTENT_FILENAME); | ||
+ createNewFile(dirFile, INDICATOR_DAEMON_ASSISTANT_FILENAME); | ||
+ return true; | ||
+ } catch (IOException e) { | ||
+ e.printStackTrace(); | ||
+ return false; | ||
+ } | ||
+ } | ||
+ | ||
+ private void createNewFile(File dirFile, String fileName) throws IOException{ | ||
+ File file = new File(dirFile, fileName); | ||
+ if(!file.exists()){ | ||
+ file.createNewFile(); | ||
+ } | ||
+ } | ||
+} |
218
LibMarsdaemon/src/main/java/com/marswin89/marsdaemon/strategy/DaemonStrategy23.java
@@ -0,0 +1,218 @@ | ||
+package com.marswin89.marsdaemon.strategy; | ||
+ | ||
+import java.io.File; | ||
+import java.io.IOException; | ||
+import java.lang.reflect.Field; | ||
+import java.lang.reflect.InvocationTargetException; | ||
+ | ||
+import android.annotation.SuppressLint; | ||
+import android.app.Activity; | ||
+import android.content.ComponentName; | ||
+import android.content.Context; | ||
+import android.content.Intent; | ||
+import android.os.IBinder; | ||
+import android.os.Parcel; | ||
+import android.os.RemoteException; | ||
+import android.util.Log; | ||
+ | ||
+import com.marswin89.marsdaemon.DaemonConfigurations; | ||
+import com.marswin89.marsdaemon.IDaemonStrategy; | ||
+import com.marswin89.marsdaemon.nativ.NativeDaemonAPI21; | ||
+/** | ||
+ * the strategy in android API 23. | ||
+ * | ||
+ * @author Mars | ||
+ * | ||
+ */ | ||
+public class DaemonStrategy23 implements IDaemonStrategy{ | ||
+ private final static String INDICATOR_DIR_NAME = "indicators"; | ||
+ private final static String INDICATOR_PERSISTENT_FILENAME = "indicator_p"; | ||
+ private final static String INDICATOR_DAEMON_ASSISTANT_FILENAME = "indicator_d"; | ||
+ private final static String OBSERVER_PERSISTENT_FILENAME = "observer_p"; | ||
+ private final static String OBSERVER_DAEMON_ASSISTANT_FILENAME = "observer_d"; | ||
+ | ||
+ private IBinder mRemote; | ||
+ private Parcel mBroadcastData; | ||
+ private DaemonConfigurations mConfigs; | ||
+ | ||
+ @Override | ||
+ public boolean onInitialization(Context context) { | ||
+ return initIndicatorFiles(context); | ||
+ } | ||
+ | ||
+ @Override | ||
+ public void onPersistentCreate(final Context context, DaemonConfigurations configs) { | ||
+ initAmsBinder(); | ||
+ initBroadcastParcel(context, configs.DAEMON_ASSISTANT_CONFIG.RECEIVER_NAME); | ||
+ sendBroadcastByAmsBinder(); | ||
+ | ||
+ Thread t = new Thread(){ | ||
+ public void run() { | ||
+ File indicatorDir = context.getDir(INDICATOR_DIR_NAME, Context.MODE_PRIVATE); | ||
+ new NativeDaemonAPI21(context).doDaemon( | ||
+ new File(indicatorDir, INDICATOR_PERSISTENT_FILENAME).getAbsolutePath(), | ||
+ new File(indicatorDir, INDICATOR_DAEMON_ASSISTANT_FILENAME).getAbsolutePath(), | ||
+ new File(indicatorDir, OBSERVER_PERSISTENT_FILENAME).getAbsolutePath(), | ||
+ new File(indicatorDir, OBSERVER_DAEMON_ASSISTANT_FILENAME).getAbsolutePath()); | ||
+ }; | ||
+ }; | ||
+ t.start(); | ||
+ | ||
+ ComponentName componentName = new ComponentName(context.getPackageName(), configs.PERSISTENT_CONFIG.SERVICE_NAME); | ||
+ Intent intent = new Intent(); | ||
+ intent.setComponent(componentName); | ||
+ context.startService(intent); | ||
+ | ||
+ if(configs != null && configs.LISTENER != null){ | ||
+ this.mConfigs = configs; | ||
+ configs.LISTENER.onPersistentStart(context); | ||
+ } | ||
+ } | ||
+ | ||
+ @Override | ||
+ public void onDaemonAssistantCreate(final Context context, DaemonConfigurations configs) { | ||
+ initAmsBinder(); | ||
+ initBroadcastParcel(context, configs.PERSISTENT_CONFIG.RECEIVER_NAME); | ||
+ sendBroadcastByAmsBinder(); | ||
+ | ||
+ Thread t = new Thread(){ | ||
+ public void run() { | ||
+ File indicatorDir = context.getDir(INDICATOR_DIR_NAME, Context.MODE_PRIVATE); | ||
+ new NativeDaemonAPI21(context).doDaemon( | ||
+ new File(indicatorDir, INDICATOR_DAEMON_ASSISTANT_FILENAME).getAbsolutePath(), | ||
+ new File(indicatorDir, INDICATOR_PERSISTENT_FILENAME).getAbsolutePath(), | ||
+ new File(indicatorDir, OBSERVER_DAEMON_ASSISTANT_FILENAME).getAbsolutePath(), | ||
+ new File(indicatorDir, OBSERVER_PERSISTENT_FILENAME).getAbsolutePath()); | ||
+ }; | ||
+ }; | ||
+ t.start(); | ||
+ | ||
+ ComponentName componentName = new ComponentName(context.getPackageName(), configs.DAEMON_ASSISTANT_CONFIG.SERVICE_NAME); | ||
+ Intent intent = new Intent(); | ||
+ intent.setComponent(componentName); | ||
+ context.startService(intent); | ||
+ | ||
+ if(configs != null && configs.LISTENER != null){ | ||
+ this.mConfigs = configs; | ||
+ configs.LISTENER.onDaemonAssistantStart(context); | ||
+ } | ||
+ } | ||
+ | ||
+ | ||
+ @Override | ||
+ public void onDaemonDead() { | ||
+ if(sendBroadcastByAmsBinder()){ | ||
+ | ||
+ if(mConfigs != null && mConfigs.LISTENER != null){ | ||
+ mConfigs.LISTENER.onWatchDaemonDaed(); | ||
+ } | ||
+ | ||
+ android.os.Process.killProcess(android.os.Process.myPid()); | ||
+ } | ||
+ } | ||
+ | ||
+ | ||
+ private void initAmsBinder(){ | ||
+ Class<?> activityManagerNative; | ||
+ try { | ||
+ activityManagerNative = Class.forName("android.app.ActivityManagerNative"); | ||
+ Object amn = activityManagerNative.getMethod("getDefault").invoke(activityManagerNative); | ||
+ Field mRemoteField = amn.getClass().getDeclaredField("mRemote"); | ||
+ mRemoteField.setAccessible(true); | ||
+ mRemote = (IBinder) mRemoteField.get(amn); | ||
+ } catch (ClassNotFoundException e) { | ||
+ e.printStackTrace(); | ||
+ } catch (IllegalAccessException e) { | ||
+ e.printStackTrace(); | ||
+ } catch (IllegalArgumentException e) { | ||
+ e.printStackTrace(); | ||
+ } catch (InvocationTargetException e) { | ||
+ e.printStackTrace(); | ||
+ } catch (NoSuchMethodException e) { | ||
+ e.printStackTrace(); | ||
+ } catch (NoSuchFieldException e) { | ||
+ e.printStackTrace(); | ||
+ } | ||
+ } | ||
+ | ||
+ | ||
+ @SuppressLint("Recycle")// when process dead, we should save time to restart and kill self, don`t take a waste of time to recycle | ||
+ private void initBroadcastParcel(Context context, String broadcastName){ | ||
+ Intent intent = new Intent(); | ||
+ ComponentName componentName = new ComponentName(context.getPackageName(), broadcastName); | ||
+ intent.setComponent(componentName); | ||
+ intent.setFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES); | ||
+ | ||
+ /* | ||
+// Object contextImpl = ((Application)context.getApplicationContext()).getBaseContext(); | ||
+ //this context is ContextImpl, get MainThread instance immediately | ||
+ Field mainThreadField = context.getClass().getDeclaredField("mMainThread"); | ||
+ mainThreadField.setAccessible(true); | ||
+ Object mainThread = mainThreadField.get(context); | ||
+ //get ApplicationThread instance | ||
+ Object applicationThread = mainThread.getClass().getMethod("getApplicationThread").invoke(mainThread); | ||
+ //get Binder | ||
+ Binder callerBinder = (Binder) (applicationThread.getClass().getMethod("asBinder").invoke(applicationThread)); | ||
+ */ | ||
+ | ||
+// UserHandle userHandle = android.os.Process.myUserHandle(); | ||
+// int handle = (Integer) userHandle.getClass().getMethod("getIdentifier").invoke(userHandle); | ||
+ | ||
+ mBroadcastData = Parcel.obtain(); | ||
+ mBroadcastData.writeInterfaceToken("android.app.IActivityManager"); | ||
+// mBroadcastData.writeStrongBinder(callerBinder); | ||
+ mBroadcastData.writeStrongBinder(null); | ||
+ intent.writeToParcel(mBroadcastData, 0); | ||
+ mBroadcastData.writeString(intent.resolveTypeIfNeeded(context.getContentResolver())); | ||
+ mBroadcastData.writeStrongBinder(null); | ||
+ mBroadcastData.writeInt(Activity.RESULT_OK); | ||
+ mBroadcastData.writeString(null); | ||
+ mBroadcastData.writeBundle(null); | ||
+ mBroadcastData.writeString(null); | ||
+ mBroadcastData.writeInt(-1); | ||
+ mBroadcastData.writeInt(0); | ||
+ mBroadcastData.writeInt(0); | ||
+// mBroadcastData.writeInt(handle); | ||
+ mBroadcastData.writeInt(0); | ||
+ } | ||
+ | ||
+ | ||
+ private boolean sendBroadcastByAmsBinder(){ | ||
+ | ||
+ try { | ||
+ if(mRemote == null || mBroadcastData == null){ | ||
+ Log.e("Daemon", "REMOTE IS NULL or PARCEL IS NULL !!!"); | ||
+ return false; | ||
+ } | ||
+ mRemote.transact(14, mBroadcastData, null, 0);//BROADCAST_INTENT_TRANSACTION = 0x00000001 + 13 | ||
+ return true; | ||
+ } catch (RemoteException e) { | ||
+ e.printStackTrace(); | ||
+ return false; | ||
+ } | ||
+ } | ||
+ | ||
+ | ||
+ | ||
+ private boolean initIndicatorFiles(Context context){ | ||
+ File dirFile = context.getDir(INDICATOR_DIR_NAME, Context.MODE_PRIVATE); | ||
+ if(!dirFile.exists()){ | ||
+ dirFile.mkdirs(); | ||
+ } | ||
+ try { | ||
+ createNewFile(dirFile, INDICATOR_PERSISTENT_FILENAME); | ||
+ createNewFile(dirFile, INDICATOR_DAEMON_ASSISTANT_FILENAME); | ||
+ return true; | ||
+ } catch (IOException e) { | ||
+ e.printStackTrace(); | ||
+ return false; | ||
+ } | ||
+ } | ||
+ | ||
+ private void createNewFile(File dirFile, String fileName) throws IOException{ | ||
+ File file = new File(dirFile, fileName); | ||
+ if(!file.exists()){ | ||
+ file.createNewFile(); | ||
+ } | ||
+ } | ||
+} |
143
LibMarsdaemon/src/main/java/com/marswin89/marsdaemon/strategy/DaemonStrategyUnder21.java
@@ -0,0 +1,143 @@ | ||
+package com.marswin89.marsdaemon.strategy; | ||
+ | ||
+import java.io.File; | ||
+import java.io.FileOutputStream; | ||
+import java.io.IOException; | ||
+import java.io.InputStream; | ||
+ | ||
+import android.app.AlarmManager; | ||
+import android.app.PendingIntent; | ||
+import android.content.ComponentName; | ||
+import android.content.Context; | ||
+import android.content.Intent; | ||
+import android.content.res.AssetManager; | ||
+import android.os.Build; | ||
+import android.os.SystemClock; | ||
+import android.text.TextUtils; | ||
+ | ||
+import com.marswin89.marsdaemon.DaemonConfigurations; | ||
+import com.marswin89.marsdaemon.IDaemonStrategy; | ||
+import com.marswin89.marsdaemon.nativ.NativeDaemonAPI20; | ||
+ | ||
+/** | ||
+ * the strategy in android API below 21. | ||
+ * | ||
+ * @author Mars | ||
+ * | ||
+ */ | ||
+public class DaemonStrategyUnder21 implements IDaemonStrategy{ | ||
+ private final String BINARY_DEST_DIR_NAME = "bin"; | ||
+ private final String BINARY_FILE_NAME = "daemon"; | ||
+ | ||
+ private AlarmManager mAlarmManager; | ||
+ private PendingIntent mPendingIntent; | ||
+ | ||
+ @Override | ||
+ public boolean onInitialization(Context context) { | ||
+ return installBinary(context); | ||
+ } | ||
+ | ||
+ @Override | ||
+ public void onPersistentCreate(final Context context, final DaemonConfigurations configs) { | ||
+ initAlarm(context, configs.DAEMON_ASSISTANT_CONFIG.SERVICE_NAME); | ||
+ Thread t = new Thread(){ | ||
+ public void run() { | ||
+ File binaryFile = new File(context.getDir(BINARY_DEST_DIR_NAME, Context.MODE_PRIVATE), BINARY_FILE_NAME); | ||
+ new NativeDaemonAPI20(context).doDaemon( | ||
+ context.getPackageName(), | ||
+ configs.DAEMON_ASSISTANT_CONFIG.SERVICE_NAME, | ||
+ binaryFile.getAbsolutePath()); | ||
+ }; | ||
+ }; | ||
+ t.setPriority(Thread.MAX_PRIORITY); | ||
+ t.start(); | ||
+ | ||
+ if(configs != null && configs.LISTENER != null){ | ||
+ configs.LISTENER.onPersistentStart(context); | ||
+ } | ||
+ } | ||
+ | ||
+ @Override | ||
+ public void onDaemonAssistantCreate(Context context, DaemonConfigurations configs) { | ||
+ Intent intent = new Intent(); | ||
+ ComponentName component = new ComponentName(context.getPackageName(), configs.PERSISTENT_CONFIG.SERVICE_NAME); | ||
+ intent.setComponent(component); | ||
+ context.startService(intent); | ||
+ if(configs != null && configs.LISTENER != null){ | ||
+ configs.LISTENER.onWatchDaemonDaed(); | ||
+ } | ||
+ android.os.Process.killProcess(android.os.Process.myPid()); | ||
+ } | ||
+ | ||
+ | ||
+ @Override | ||
+ public void onDaemonDead() { | ||
+ mAlarmManager.setRepeating(AlarmManager.ELAPSED_REALTIME, SystemClock.elapsedRealtime(), 100, mPendingIntent); | ||
+ android.os.Process.killProcess(android.os.Process.myPid()); | ||
+ } | ||
+ | ||
+ | ||
+ private void initAlarm(Context context, String serviceName){ | ||
+ if(mAlarmManager == null){ | ||
+ mAlarmManager = ((AlarmManager)context.getSystemService(Context.ALARM_SERVICE)); | ||
+ } | ||
+ if(mPendingIntent == null){ | ||
+ Intent intent = new Intent(); | ||
+ ComponentName component = new ComponentName(context.getPackageName(), serviceName); | ||
+ intent.setComponent(component); | ||
+ intent.setFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES); | ||
+ mPendingIntent = PendingIntent.getService(context, 0, intent, 0); | ||
+ } | ||
+ mAlarmManager.cancel(mPendingIntent); | ||
+ } | ||
+ | ||
+ | ||
+ private boolean installBinary(Context context){ | ||
+ String binaryDirName = null; | ||
+ String abi = Build.CPU_ABI; | ||
+ if (abi.startsWith("armeabi-v7a")) { | ||
+ binaryDirName = "armeabi-v7a"; | ||
+ }else if(abi.startsWith("x86")) { | ||
+ binaryDirName = "x86"; | ||
+ }else{ | ||
+ binaryDirName = "armeabi"; | ||
+ } | ||
+ return install(context, BINARY_DEST_DIR_NAME, binaryDirName, BINARY_FILE_NAME); | ||
+ } | ||
+ | ||
+ | ||
+ private boolean install(Context context, String destDirName, String assetsDirName, String filename) { | ||
+ File file = new File(context.getDir(destDirName, Context.MODE_PRIVATE), filename); | ||
+ if (file.exists()) { | ||
+ return true; | ||
+ } | ||
+ try { | ||
+ copyAssets(context, (TextUtils.isEmpty(assetsDirName) ? "" : (assetsDirName + File.separator)) + filename, file, "700"); | ||
+ return true; | ||
+ } catch (Exception e) { | ||
+ return false; | ||
+ } | ||
+ } | ||
+ | ||
+ private void copyAssets(Context context, String assetsFilename, File file, String mode) throws IOException, InterruptedException { | ||
+ AssetManager manager = context.getAssets(); | ||
+ final InputStream is = manager.open(assetsFilename); | ||
+ copyFile(file, is, mode); | ||
+ } | ||
+ | ||
+ private void copyFile(File file, InputStream is, String mode) throws IOException, InterruptedException { | ||
+ if(!file.getParentFile().exists()){ | ||
+ file.getParentFile().mkdirs(); | ||
+ } | ||
+ final String abspath = file.getAbsolutePath(); | ||
+ final FileOutputStream out = new FileOutputStream(file); | ||
+ byte buf[] = new byte[1024]; | ||
+ int len; | ||
+ while ((len = is.read(buf)) > 0) { | ||
+ out.write(buf, 0, len); | ||
+ } | ||
+ out.close(); | ||
+ is.close(); | ||
+ Runtime.getRuntime().exec("chmod " + mode + " " + abspath).waitFor(); | ||
+ } | ||
+} |
215
LibMarsdaemon/src/main/java/com/marswin89/marsdaemon/strategy/DaemonStrategyXiaomi.java
@@ -0,0 +1,215 @@ | ||
+package com.marswin89.marsdaemon.strategy; | ||
+ | ||
+import java.io.File; | ||
+import java.io.FileOutputStream; | ||
+import java.io.IOException; | ||
+import java.io.InputStream; | ||
+import java.lang.reflect.Field; | ||
+import java.lang.reflect.InvocationTargetException; | ||
+ | ||
+import android.annotation.SuppressLint; | ||
+import android.content.ComponentName; | ||
+import android.content.Context; | ||
+import android.content.Intent; | ||
+import android.content.res.AssetManager; | ||
+import android.os.IBinder; | ||
+import android.os.Parcel; | ||
+import android.os.RemoteException; | ||
+import android.text.TextUtils; | ||
+import android.util.Log; | ||
+ | ||
+import com.marswin89.marsdaemon.DaemonConfigurations; | ||
+import com.marswin89.marsdaemon.IDaemonStrategy; | ||
+import com.marswin89.marsdaemon.nativ.NativeDaemonAPI20; | ||
+ | ||
+/** | ||
+ * the strategy in Mi. | ||
+ * | ||
+ * @author Mars | ||
+ * | ||
+ */ | ||
+public class DaemonStrategyXiaomi implements IDaemonStrategy{ | ||
+ private final String BINARY_DEST_DIR_NAME = "bin"; | ||
+ private final String BINARY_FILE_NAME = "daemon"; | ||
+ | ||
+ private IBinder mRemote; | ||
+ private Parcel mServiceData; | ||
+ private DaemonConfigurations mConfigs; | ||
+ | ||
+ @Override | ||
+ public boolean onInitialization(Context context) { | ||
+ return installBinary(context); | ||
+ } | ||
+ | ||
+ @Override | ||
+ public void onPersistentCreate(final Context context, final DaemonConfigurations configs) { | ||
+ initAmsBinder(); | ||
+ initServiceParcel(context, configs.DAEMON_ASSISTANT_CONFIG.SERVICE_NAME); | ||
+ Thread t = new Thread(){ | ||
+ public void run() { | ||
+ File binaryFile = new File(context.getDir(BINARY_DEST_DIR_NAME, Context.MODE_PRIVATE), BINARY_FILE_NAME); | ||
+ new NativeDaemonAPI20(context).doDaemon( | ||
+ context.getPackageName(), | ||
+ configs.DAEMON_ASSISTANT_CONFIG.SERVICE_NAME, | ||
+ binaryFile.getAbsolutePath()); | ||
+ }; | ||
+ }; | ||
+ t.setPriority(Thread.MAX_PRIORITY); | ||
+ t.start(); | ||
+ | ||
+ if(configs != null && configs.LISTENER != null){ | ||
+ this.mConfigs = configs; | ||
+ configs.LISTENER.onPersistentStart(context); | ||
+ } | ||
+ | ||
+ } | ||
+ | ||
+ | ||
+ @Override | ||
+ public void onDaemonAssistantCreate(Context context, DaemonConfigurations configs) { | ||
+ Intent intent = new Intent(); | ||
+ ComponentName component = new ComponentName(context.getPackageName(), configs.PERSISTENT_CONFIG.SERVICE_NAME); | ||
+ intent.setComponent(component); | ||
+ context.startService(intent); | ||
+ if(configs != null && configs.LISTENER != null){ | ||
+ configs.LISTENER.onWatchDaemonDaed(); | ||
+ } | ||
+ android.os.Process.killProcess(android.os.Process.myPid()); | ||
+ } | ||
+ | ||
+ @Override | ||
+ public void onDaemonDead() { | ||
+ if(startServiceByAmsBinder()){ | ||
+ | ||
+ if(mConfigs != null && mConfigs.LISTENER != null){ | ||
+ mConfigs.LISTENER.onWatchDaemonDaed(); | ||
+ } | ||
+ | ||
+ android.os.Process.killProcess(android.os.Process.myPid()); | ||
+ } | ||
+ } | ||
+ | ||
+ private void initAmsBinder(){ | ||
+ Class<?> activityManagerNative; | ||
+ try { | ||
+ activityManagerNative = Class.forName("android.app.ActivityManagerNative"); | ||
+ Object amn = activityManagerNative.getMethod("getDefault").invoke(activityManagerNative); | ||
+ Field mRemoteField = amn.getClass().getDeclaredField("mRemote"); | ||
+ mRemoteField.setAccessible(true); | ||
+ mRemote = (IBinder) mRemoteField.get(amn); | ||
+ } catch (ClassNotFoundException e) { | ||
+ e.printStackTrace(); | ||
+ } catch (IllegalAccessException e) { | ||
+ e.printStackTrace(); | ||
+ } catch (IllegalArgumentException e) { | ||
+ e.printStackTrace(); | ||
+ } catch (InvocationTargetException e) { | ||
+ e.printStackTrace(); | ||
+ } catch (NoSuchMethodException e) { | ||
+ e.printStackTrace(); | ||
+ } catch (NoSuchFieldException e) { | ||
+ e.printStackTrace(); | ||
+ } | ||
+ } | ||
+ | ||
+ | ||
+ @SuppressLint("Recycle")// when process dead, we should save time to restart and kill self, don`t take a waste of time to recycle | ||
+ private void initServiceParcel(Context context, String serviceName){ | ||
+ Intent intent = new Intent(); | ||
+ ComponentName component = new ComponentName(context.getPackageName(), serviceName); | ||
+ intent.setComponent(component); | ||
+ | ||
+ /* | ||
+ //get ContextImpl instance | ||
+// Object contextImpl = ((Application)context.getApplicationContext()).getBaseContext(); | ||
+ //this context is ContextImpl, get MainThread instance immediately | ||
+ Field mainThreadField = context.getClass().getDeclaredField("mMainThread"); | ||
+ mainThreadField.setAccessible(true); | ||
+ Object mainThread = mainThreadField.get(context); | ||
+ //get ApplicationThread instance | ||
+ Object applicationThread = mainThread.getClass().getMethod("getApplicationThread").invoke(mainThread); | ||
+ //get Binder | ||
+ Binder callerBinder = (Binder) (applicationThread.getClass().getMethod("asBinder").invoke(applicationThread)); | ||
+ */ | ||
+ | ||
+ //get handle | ||
+// UserHandle userHandle = android.os.Process.myUserHandle(); | ||
+// int handle = (Integer) userHandle.getClass().getMethod("getIdentifier").invoke(userHandle); | ||
+ | ||
+ //write pacel | ||
+ mServiceData = Parcel.obtain(); | ||
+ mServiceData.writeInterfaceToken("android.app.IActivityManager"); | ||
+ mServiceData.writeStrongBinder(null); | ||
+// mServiceData.writeStrongBinder(callerBinder); | ||
+ intent.writeToParcel(mServiceData, 0); | ||
+ mServiceData.writeString(null); | ||
+// mServiceData.writeString(intent.resolveTypeIfNeeded(context.getContentResolver())); | ||
+ mServiceData.writeInt(0); | ||
+// mServiceData.writeInt(handle); | ||
+ | ||
+ } | ||
+ | ||
+ private boolean startServiceByAmsBinder(){ | ||
+ try { | ||
+ if(mRemote == null || mServiceData == null){ | ||
+ Log.e("Daemon", "REMOTE IS NULL or PARCEL IS NULL !!!"); | ||
+ return false; | ||
+ } | ||
+ mRemote.transact(34, mServiceData, null, 0);//START_SERVICE_TRANSACTION = 34 | ||
+ return true; | ||
+ } catch (RemoteException e) { | ||
+ e.printStackTrace(); | ||
+ return false; | ||
+ } | ||
+ } | ||
+ | ||
+ private boolean installBinary(Context context){ | ||
+ String binaryDirName = null; | ||
+// String abi = Build.CPU_ABI; | ||
+// if (abi.startsWith("armeabi-v7a")) { | ||
+// binaryDirName = "armeabi-v7a"; | ||
+// }else if(abi.startsWith("x86")) { | ||
+// binaryDirName = "x86"; | ||
+// }else{ | ||
+// binaryDirName = "armeabi"; | ||
+// } | ||
+ return install(context, BINARY_DEST_DIR_NAME, binaryDirName, BINARY_FILE_NAME); | ||
+ } | ||
+ | ||
+ | ||
+ private boolean install(Context context, String destDirName, String assetsDirName, String filename) { | ||
+ File file = new File(context.getDir(destDirName, Context.MODE_PRIVATE), filename); | ||
+ if (file.exists()) { | ||
+ return true; | ||
+ } | ||
+ try { | ||
+ copyAssets(context, (TextUtils.isEmpty(assetsDirName) ? "" : (assetsDirName + File.separator)) + filename, file, "700"); | ||
+ return true; | ||
+ } catch (Exception e) { | ||
+ return false; | ||
+ } | ||
+ } | ||
+ | ||
+ private void copyAssets(Context context, String assetsFilename, File file, String mode) throws IOException, InterruptedException { | ||
+ AssetManager manager = context.getAssets(); | ||
+ final InputStream is = manager.open(assetsFilename); | ||
+ copyFile(file, is, mode); | ||
+ } | ||
+ | ||
+ private void copyFile(File file, InputStream is, String mode) throws IOException, InterruptedException { | ||
+ if(!file.getParentFile().exists()){ | ||
+ file.getParentFile().mkdirs(); | ||
+ } | ||
+ final String abspath = file.getAbsolutePath(); | ||
+ final FileOutputStream out = new FileOutputStream(file); | ||
+ byte buf[] = new byte[1024]; | ||
+ int len; | ||
+ while ((len = is.read(buf)) > 0) { | ||
+ out.write(buf, 0, len); | ||
+ } | ||
+ out.close(); | ||
+ is.close(); | ||
+ Runtime.getRuntime().exec("chmod " + mode + " " + abspath).waitFor(); | ||
+ } | ||
+ | ||
+} |
3
LibMarsdaemon/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@ | ||
+<resources> | ||
+ <string name="app_name">Marsdaemon</string> | ||
+</resources> |
15
LibMarsdaemon/src/test/java/com/marswin89/marsdaemon/ExampleUnitTest.java
@@ -0,0 +1,15 @@ | ||
+package com.marswin89.marsdaemon; | ||
+ | ||
+import org.junit.Test; | ||
+ | ||
+import static org.junit.Assert.*; | ||
+ | ||
+/** | ||
+ * To work on unit tests, switch the Test Artifact in the Build Variants view. | ||
+ */ | ||
+public class ExampleUnitTest { | ||
+ @Test | ||
+ public void addition_isCorrect() throws Exception { | ||
+ assertEquals(4, 2 + 2); | ||
+ } | ||
+} |
19
Marsdaemon2.iml
@@ -0,0 +1,19 @@ | ||
+<?xml version="1.0" encoding="UTF-8"?> | ||
+<module external.linked.project.id="Marsdaemon2" external.linked.project.path="$MODULE_DIR$" external.root.project.path="$MODULE_DIR$" external.system.id="GRADLE" external.system.module.group="" external.system.module.version="unspecified" type="JAVA_MODULE" version="4"> | ||
+ <component name="FacetManager"> | ||
+ <facet type="java-gradle" name="Java-Gradle"> | ||
+ <configuration> | ||
+ <option name="BUILD_FOLDER_PATH" value="$MODULE_DIR$/build" /> | ||
+ <option name="BUILDABLE" value="false" /> | ||
+ </configuration> | ||
+ </facet> | ||
+ </component> | ||
+ <component name="NewModuleRootManager" LANGUAGE_LEVEL="JDK_1_7" inherit-compiler-output="true"> | ||
+ <exclude-output /> | ||
+ <content url="file://$MODULE_DIR$"> | ||
+ <excludeFolder url="file://$MODULE_DIR$/.gradle" /> | ||
+ </content> | ||
+ <orderEntry type="inheritedJdk" /> | ||
+ <orderEntry type="sourceFolder" forTests="false" /> | ||
+ </component> | ||
+</module> |
88
README.md
@@ -1,2 +1,88 @@ | ||
# MarsDaemon | ||
-A light library, you can make your project depend it easily, and your project will be UNDEAD (contains api from 9 to 23, lol). | ||
+ | ||
+It is a lite library, you can make your project depend it easily, and your project will be UNDEAD. | ||
+ | ||
+ * support keeping alive from ADNROID_API 9 to ANDRIOD_API 23 | ||
+ * support keeping alive in most of devices(contains SUMSUNG\HUAWEI\MEIZU\MI\NEXUS..) | ||
+ * support keeping alive in FORCE_CLOSE from SystemSettings and MEMORY_CLEAN from third-part apps (such like CleanMaster\360 and so on) | ||
+ * surpports to keep BOOT_RECEIVER work well simplely | ||
+ | ||
+ | ||
+### Version | ||
+1.0 | ||
+ | ||
+## Installation | ||
+#### STEP1 | ||
+make your project depend on LibMarsdaemon, and regist 2 Service and 2 BroadcastReceiver in your manifests in 2 different process. | ||
+ | ||
+```sh | ||
+<service android:name=".Service1" android:process=":process1"/> | ||
+<receiver android:name=".Receiver1" android:process=":process1"/> | ||
+<service android:name=".Service2" android:process=":process2"/> | ||
+<receiver android:name=".Receiver2" android:process=":process2"/> | ||
+``` | ||
+ | ||
+Service1 is the Service which you want to be undead, you can do somethings in it. | ||
+ | ||
+But the others is used by Marsdaemon, so DONNOT do anything inside. | ||
+ | ||
+#### STEP2 | ||
+make your application extends DaemonApplication and override the method getDaemonConfigurations(). Return back the confugirations. | ||
+```sh | ||
+@Override | ||
+protected DaemonConfigurations getDaemonConfigurations() { | ||
+ DaemonConfigurations.DaemonConfiguration configuration1 = new DaemonConfigurations.DaemonConfiguration("com.marswin89.marsdaemon.demo:process1", Service1.class.getCanonicalName(), Receiver1.class.getCanonicalName()); | ||
+ DaemonConfigurations.DaemonConfiguration configuration2 = new DaemonConfigurations.DaemonConfiguration("com.marswin89.marsdaemon.demo:process2", Service2.class.getCanonicalName(), Receiver2.class.getCanonicalName()); | ||
+ DaemonConfigurations.DaemonListener listener = new MyDaemonListener(); | ||
+ //return new DaemonConfigurations(configuration1, configuration2);//listener can be null | ||
+ return new DaemonConfigurations(configuration1, configuration2, listener); | ||
+} | ||
+``` | ||
+if you want to override attachBaseContext you will find it had been defined final by me. you can override attachBaseContextByDaemon instead it. | ||
+ | ||
+see more details in MyApplication1 in Demo | ||
+ | ||
+##### if your application has extends another application, you should create a DaemonClient and perfrom it in attachBaseContext(), DONOT forget perform super.attachBaseContext() before! | ||
+ | ||
+```sh | ||
+private DaemonClient mDaemonClient; | ||
+@Override | ||
+protected void attachBaseContext(Context base) { | ||
+ super.attachBaseContext(base); | ||
+ mDaemonClient = new DaemonClient(createDaemonConfigurations()); | ||
+ mDaemonClient.onAttachBaseContext(base); | ||
+} | ||
+``` | ||
+see more details in MyApplication2 in DemoMarsdaemon | ||
+ | ||
+#### STEP3 | ||
+Launch the Service once, and try to kill it. | ||
+ | ||
+## | ||
+## | ||
+## | ||
+## Contact me | ||
+Email: Marswin89@gmail.com | ||
+ | ||
+ | ||
+## | ||
+## | ||
+## | ||
+ | ||
+License | ||
+---- | ||
+ | ||
+Copyright (C) 2015, Mars Kwok | ||
+ | ||
+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. | ||
+ |
23
build.gradle
@@ -0,0 +1,23 @@ | ||
+// Top-level build file where you can add configuration options common to all sub-projects/modules. | ||
+ | ||
+buildscript { | ||
+ repositories { | ||
+ jcenter() | ||
+ } | ||
+ dependencies { | ||
+ classpath 'com.android.tools.build:gradle:1.3.0' | ||
+ | ||
+ // NOTE: Do not place your application dependencies here; they belong | ||
+ // in the individual module build.gradle files | ||
+ } | ||
+} | ||
+ | ||
+allprojects { | ||
+ repositories { | ||
+ jcenter() | ||
+ } | ||
+} | ||
+ | ||
+task clean(type: Delete) { | ||
+ delete rootProject.buildDir | ||
+} |
12
build/intermediates/dex-cache/cache.xml
@@ -0,0 +1,12 @@ | ||
+<?xml version="1.0" encoding="utf-8"?> | ||
+<items version="2" > | ||
+ | ||
+ <item | ||
+ jar="/Users/guoyang/Workspace/workspace_github/Marsdaemon2/DemoMarsdaemon/build/intermediates/exploded-aar/Marsdaemon2/LibMarsdaemon/unspecified/jars/classes.jar" | ||
+ jumboMode="false" | ||
+ revision="23.0.2" | ||
+ sha1="43b527e25decf1d24c3365c600eef0f5b01ba06e"> | ||
+ <dex dex="/Users/guoyang/Workspace/workspace_github/Marsdaemon2/DemoMarsdaemon/build/intermediates/pre-dexed/debug/classes-9e71f3a69a7a75f0e6ad61f439036846c69c2471.jar" /> | ||
+ </item> | ||
+ | ||
+</items> |
18
gradle.properties
@@ -0,0 +1,18 @@ | ||
+# Project-wide Gradle settings. | ||
+ | ||
+# IDE (e.g. Android Studio) users: | ||
+# Gradle settings configured through the IDE *will override* | ||
+# any settings specified in this file. | ||
+ | ||
+# 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: -Xmx10248m -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 |
BIN
gradle/wrapper/gradle-wrapper.jar
Binary file not shown.
6
gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,6 @@ | ||
+#Wed Oct 21 11:34:03 PDT 2015 | ||
+distributionBase=GRADLE_USER_HOME | ||
+distributionPath=wrapper/dists | ||
+zipStoreBase=GRADLE_USER_HOME | ||
+zipStorePath=wrapper/dists | ||
+distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip |
160
gradlew
@@ -0,0 +1,160 @@ | ||
+#!/usr/bin/env bash | ||
+ | ||
+############################################################################## | ||
+## | ||
+## Gradle start up script for UN*X | ||
+## | ||
+############################################################################## | ||
+ | ||
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. | ||
+DEFAULT_JVM_OPTS="" | ||
+ | ||
+APP_NAME="Gradle" | ||
+APP_BASE_NAME=`basename "$0"` | ||
+ | ||
+# 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 | ||
+case "`uname`" in | ||
+ CYGWIN* ) | ||
+ cygwin=true | ||
+ ;; | ||
+ Darwin* ) | ||
+ darwin=true | ||
+ ;; | ||
+ MINGW* ) | ||
+ msys=true | ||
+ ;; | ||
+esac | ||
+ | ||
+# 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 | ||
+ | ||
+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" ] ; 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 | ||
+ | ||
+# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules | ||
+function splitJvmOpts() { | ||
+ JVM_OPTS=("$@") | ||
+} | ||
+eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS | ||
+JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" | ||
+ | ||
+exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" |
90
gradlew.bat
@@ -0,0 +1,90 @@ | ||
+@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 | ||
+ | ||
+@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= | ||
+ | ||
+set DIRNAME=%~dp0 | ||
+if "%DIRNAME%" == "" set DIRNAME=. | ||
+set APP_BASE_NAME=%~n0 | ||
+set APP_HOME=%DIRNAME% | ||
+ | ||
+@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 Windowz variants | ||
+ | ||
+if not "%OS%" == "Windows_NT" goto win9xME_args | ||
+if "%@eval[2+2]" == "4" goto 4NT_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=%* | ||
+goto execute | ||
+ | ||
+:4NT_args | ||
+@rem Get arguments from the 4NT Shell from JP Software | ||
+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 |
10
local.properties
@@ -0,0 +1,10 @@ | ||
+## This file is automatically generated by Android Studio. | ||
+# Do not modify this file -- YOUR CHANGES WILL BE ERASED! | ||
+# | ||
+# This file should *NOT* be checked into Version Control Systems, | ||
+# as it contains information specific to your local configuration. | ||
+# | ||
+# Location of the SDK. This is only used by Gradle. | ||
+# For customization when using a Version Control System, please read the | ||
+# header note. | ||
+sdk.dir=/Users/guoyang/Developer/android-sdk-macosx |
1
settings.gradle
@@ -0,0 +1 @@ | ||
+include ':DemoMarsdaemon', ':LibMarsdaemon' |
0 comments on commit
742759c