DaemonConfigurations.java
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();
}
}
DaemonClient.java
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 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();
}
}
IDaemonStrategy.java
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
if
(Build.MODEL !=
null
&& Build.MODEL.toLowerCase().startsWith(
"a31"
)){
mDaemonStrategy =
new
DaemonStrategy21();
}
else
{
mDaemonStrategy =
new
DaemonStrategyUnder21();
}
break
;
}
return
mDaemonStrategy;
}
}
}
PackageUtils.java
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;
}
}
IDaemonClient.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
|
package
com.marswin89.marsdaemon;
import
android.content.Context;
/**
*
* @author Mars
*
*/
public
interface
IDaemonClient {
/**
* override this method by {@link android.app.Application}
* ****************************************************************
* DO super.attchBaseContext() first !
* ****************************************************************
*
* @param base
*/
void
onAttachBaseContext(Context base);
}
|
NativeDaemonBase.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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();
}
}
|
DaemonStrategy23.java
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();
}
}
}
DaemonStrategyXiaomi.java
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();
}
}
DaemonStrategy21.java
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(){