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