Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
S
SandHook
Project
Project
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
Administrator
SandHook
Commits
aa9be549
Commit
aa9be549
authored
Apr 02, 2019
by
swift_gan
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
remove useless code of xposed
parent
08c68ea5
Hide whitespace changes
Inline
Side-by-side
Showing
12 changed files
with
4 additions
and
1229 deletions
+4
-1229
DynamicBridge.java
.../swift/sandhook/xposedcompat/methodgen/DynamicBridge.java
+0
-27
DexCreator.java
...mpat/src/main/java/de/robv/android/xposed/DexCreator.java
+0
-235
SELinuxHelper.java
...t/src/main/java/de/robv/android/xposed/SELinuxHelper.java
+0
-81
XSharedPreferences.java
.../main/java/de/robv/android/xposed/XSharedPreferences.java
+2
-63
XposedBridge.java
...at/src/main/java/de/robv/android/xposed/XposedBridge.java
+2
-179
XposedInit.java
...mpat/src/main/java/de/robv/android/xposed/XposedInit.java
+0
-68
BaseService.java
...ain/java/de/robv/android/xposed/services/BaseService.java
+0
-179
BinderService.java
...n/java/de/robv/android/xposed/services/BinderService.java
+0
-166
DirectAccessService.java
.../de/robv/android/xposed/services/DirectAccessService.java
+0
-113
FileResult.java
...main/java/de/robv/android/xposed/services/FileResult.java
+0
-60
ZygoteService.java
...n/java/de/robv/android/xposed/services/ZygoteService.java
+0
-54
package-info.java
...in/java/de/robv/android/xposed/services/package-info.java
+0
-4
No files found.
xposedcompat/src/main/java/com/swift/sandhook/xposedcompat/methodgen/DynamicBridge.java
View file @
aa9be549
...
...
@@ -106,33 +106,6 @@ public final class DynamicBridge {
return
false
;
}
}
public
static
Object
invokeOriginalMethod
(
Member
method
,
Object
thisObject
,
Object
[]
args
)
throws
Throwable
{
Method
callBackup
=
hookedInfo
.
get
(
method
);
if
(
callBackup
==
null
)
{
//method hook use internal stub
return
SandHook
.
callOriginMethod
(
method
,
thisObject
,
args
);
}
if
(!
Modifier
.
isStatic
(
callBackup
.
getModifiers
()))
{
throw
new
IllegalStateException
(
"original method is not static, something must be wrong!"
);
}
callBackup
.
setAccessible
(
true
);
if
(
args
==
null
)
{
args
=
new
Object
[
0
];
}
final
int
argsSize
=
args
.
length
;
if
(
Modifier
.
isStatic
(
method
.
getModifiers
()))
{
return
callBackup
.
invoke
(
null
,
args
);
}
else
{
Object
[]
newArgs
=
new
Object
[
argsSize
+
1
];
newArgs
[
0
]
=
thisObject
;
for
(
int
i
=
1
;
i
<
newArgs
.
length
;
i
++)
{
newArgs
[
i
]
=
args
[
i
-
1
];
}
return
callBackup
.
invoke
(
null
,
newArgs
);
}
}
}
xposedcompat/src/main/java/de/robv/android/xposed/DexCreator.java
deleted
100644 → 0
View file @
08c68ea5
package
de
.
robv
.
android
.
xposed
;
import
android.os.Environment
;
import
java.io.ByteArrayOutputStream
;
import
java.io.File
;
import
java.io.FileInputStream
;
import
java.io.FileOutputStream
;
import
java.io.IOException
;
import
java.io.OutputStream
;
import
java.security.DigestException
;
import
java.security.MessageDigest
;
import
java.security.NoSuchAlgorithmException
;
import
java.util.zip.Adler32
;
import
static
de
.
robv
.
android
.
xposed
.
XposedHelpers
.
inputStreamToByteArray
;
/**
* Helper class which can create a very simple .dex file, containing only a class definition
* with a super class (no methods, fields, ...).
*/
/*package*/
class
DexCreator
{
public
static
File
DALVIK_CACHE
=
new
File
(
Environment
.
getDataDirectory
(),
"dalvik-cache"
);
/** Returns the default dex file name for the class. */
public
static
File
getDefaultFile
(
String
childClz
)
{
return
new
File
(
DALVIK_CACHE
,
"xposed_"
+
childClz
.
substring
(
childClz
.
lastIndexOf
(
'.'
)
+
1
)
+
".dex"
);
}
/**
* Creates (or returns) the path to a dex file which defines the superclass of {@clz} as extending
* {@code realSuperClz}, which by itself must extend {@code topClz}.
*/
public
static
File
ensure
(
String
clz
,
Class
<?>
realSuperClz
,
Class
<?>
topClz
)
throws
IOException
{
if
(!
topClz
.
isAssignableFrom
(
realSuperClz
))
{
throw
new
ClassCastException
(
"Cannot initialize "
+
clz
+
" because "
+
realSuperClz
+
" does not extend "
+
topClz
);
}
try
{
return
ensure
(
"xposed.dummy."
+
clz
+
"SuperClass"
,
realSuperClz
);
}
catch
(
IOException
e
)
{
throw
new
IOException
(
"Failed to create a superclass for "
+
clz
,
e
);
}
}
/** Like {@link #ensure(File, String, String)}, just for the default dex file name. */
public
static
File
ensure
(
String
childClz
,
Class
<?>
superClz
)
throws
IOException
{
return
ensure
(
getDefaultFile
(
childClz
),
childClz
,
superClz
.
getName
());
}
/**
* Makes sure that the given file is a simple dex file containing the given classes.
* Creates the file if that's not the case.
*/
public
static
File
ensure
(
File
file
,
String
childClz
,
String
superClz
)
throws
IOException
{
// First check if a valid file exists.
try
{
byte
[]
dex
=
inputStreamToByteArray
(
new
FileInputStream
(
file
));
if
(
matches
(
dex
,
childClz
,
superClz
))
{
return
file
;
}
else
{
file
.
delete
();
}
}
catch
(
IOException
e
)
{
file
.
delete
();
}
// If not, create a new dex file.
byte
[]
dex
=
create
(
childClz
,
superClz
);
FileOutputStream
fos
=
new
FileOutputStream
(
file
);
fos
.
write
(
dex
);
fos
.
close
();
return
file
;
}
/**
* Checks whether the Dex file fits to the class names.
* Assumes that the file has been created with this class.
*/
public
static
boolean
matches
(
byte
[]
dex
,
String
childClz
,
String
superClz
)
throws
IOException
{
boolean
childFirst
=
childClz
.
compareTo
(
superClz
)
<
0
;
byte
[]
childBytes
=
stringToBytes
(
"L"
+
childClz
.
replace
(
'.'
,
'/'
)
+
";"
);
byte
[]
superBytes
=
stringToBytes
(
"L"
+
superClz
.
replace
(
'.'
,
'/'
)
+
";"
);
int
pos
=
0xa0
;
if
(
pos
+
childBytes
.
length
+
superBytes
.
length
>=
dex
.
length
)
{
return
false
;
}
for
(
byte
b
:
childFirst
?
childBytes
:
superBytes
)
{
if
(
dex
[
pos
++]
!=
b
)
{
return
false
;
}
}
for
(
byte
b
:
childFirst
?
superBytes:
childBytes
)
{
if
(
dex
[
pos
++]
!=
b
)
{
return
false
;
}
}
return
true
;
}
/** Creates the byte array for the dex file. */
public
static
byte
[]
create
(
String
childClz
,
String
superClz
)
throws
IOException
{
boolean
childFirst
=
childClz
.
compareTo
(
superClz
)
<
0
;
byte
[]
childBytes
=
stringToBytes
(
"L"
+
childClz
.
replace
(
'.'
,
'/'
)
+
";"
);
byte
[]
superBytes
=
stringToBytes
(
"L"
+
superClz
.
replace
(
'.'
,
'/'
)
+
";"
);
int
stringsSize
=
childBytes
.
length
+
superBytes
.
length
;
int
padding
=
-
stringsSize
&
3
;
stringsSize
+=
padding
;
ByteArrayOutputStream
out
=
new
ByteArrayOutputStream
();
// header
out
.
write
(
"dex\n035\0"
.
getBytes
());
// magic
out
.
write
(
new
byte
[
24
]);
// placeholder for checksum and signature
writeInt
(
out
,
0xfc
+
stringsSize
);
// file size
writeInt
(
out
,
0x70
);
// header size
writeInt
(
out
,
0x12345678
);
// endian constant
writeInt
(
out
,
0
);
// link size
writeInt
(
out
,
0
);
// link offset
writeInt
(
out
,
0xa4
+
stringsSize
);
// map offset
writeInt
(
out
,
2
);
// strings count
writeInt
(
out
,
0x70
);
// strings offset
writeInt
(
out
,
2
);
// types count
writeInt
(
out
,
0x78
);
// types offset
writeInt
(
out
,
0
);
// prototypes count
writeInt
(
out
,
0
);
// prototypes offset
writeInt
(
out
,
0
);
// fields count
writeInt
(
out
,
0
);
// fields offset
writeInt
(
out
,
0
);
// methods count
writeInt
(
out
,
0
);
// methods offset
writeInt
(
out
,
1
);
// classes count
writeInt
(
out
,
0x80
);
// classes offset
writeInt
(
out
,
0x5c
+
stringsSize
);
// data size
writeInt
(
out
,
0xa0
);
// data offset
// string map
writeInt
(
out
,
0xa0
);
writeInt
(
out
,
0xa0
+
(
childFirst
?
childBytes
.
length
:
superBytes
.
length
));
// types
writeInt
(
out
,
0
);
// first type = first string
writeInt
(
out
,
1
);
// second type = second string
// class definitions
writeInt
(
out
,
childFirst
?
0
:
1
);
// class to define = child type
writeInt
(
out
,
1
);
// access flags = public
writeInt
(
out
,
childFirst
?
1
:
0
);
// super class = super type
writeInt
(
out
,
0
);
// no interface
writeInt
(
out
,
-
1
);
// no source file
writeInt
(
out
,
0
);
// no annotations
writeInt
(
out
,
0
);
// no class data
writeInt
(
out
,
0
);
// no static values
// string data
out
.
write
(
childFirst
?
childBytes
:
superBytes
);
out
.
write
(
childFirst
?
superBytes
:
childBytes
);
out
.
write
(
new
byte
[
padding
]);
// annotations
writeInt
(
out
,
0
);
// no items
// map
writeInt
(
out
,
7
);
// items count
writeMapItem
(
out
,
0
,
1
,
0
);
// header
writeMapItem
(
out
,
1
,
2
,
0x70
);
// strings
writeMapItem
(
out
,
2
,
2
,
0x78
);
// types
writeMapItem
(
out
,
6
,
1
,
0x80
);
// classes
writeMapItem
(
out
,
0x2002
,
2
,
0xa0
);
// string data
writeMapItem
(
out
,
0x1003
,
1
,
0xa0
+
stringsSize
);
// annotations
writeMapItem
(
out
,
0x1000
,
1
,
0xa4
+
stringsSize
);
// map list
byte
[]
buf
=
out
.
toByteArray
();
updateSignature
(
buf
);
updateChecksum
(
buf
);
return
buf
;
}
private
static
void
updateSignature
(
byte
[]
dex
)
{
// Update SHA-1 signature
try
{
MessageDigest
md
=
MessageDigest
.
getInstance
(
"SHA-1"
);
md
.
update
(
dex
,
32
,
dex
.
length
-
32
);
md
.
digest
(
dex
,
12
,
20
);
}
catch
(
NoSuchAlgorithmException
|
DigestException
e
)
{
throw
new
RuntimeException
(
e
);
}
}
private
static
void
updateChecksum
(
byte
[]
dex
)
{
// Update Adler32 checksum
Adler32
a32
=
new
Adler32
();
a32
.
update
(
dex
,
12
,
dex
.
length
-
12
);
int
chksum
=
(
int
)
a32
.
getValue
();
dex
[
8
]
=
(
byte
)
(
chksum
&
0xff
);
dex
[
9
]
=
(
byte
)
(
chksum
>>
8
&
0xff
);
dex
[
10
]
=
(
byte
)
(
chksum
>>
16
&
0xff
);
dex
[
11
]
=
(
byte
)
(
chksum
>>
24
&
0xff
);
}
private
static
void
writeUleb128
(
OutputStream
out
,
int
value
)
throws
IOException
{
while
(
value
>
0x7f
)
{
out
.
write
((
value
&
0x7f
)
|
0x80
);
value
>>>=
7
;
}
out
.
write
(
value
);
}
private
static
void
writeInt
(
OutputStream
out
,
int
value
)
throws
IOException
{
out
.
write
(
value
);
out
.
write
(
value
>>
8
);
out
.
write
(
value
>>
16
);
out
.
write
(
value
>>
24
);
}
private
static
void
writeMapItem
(
OutputStream
out
,
int
type
,
int
count
,
int
offset
)
throws
IOException
{
writeInt
(
out
,
type
);
writeInt
(
out
,
count
);
writeInt
(
out
,
offset
);
}
private
static
byte
[]
stringToBytes
(
String
s
)
throws
IOException
{
ByteArrayOutputStream
bytes
=
new
ByteArrayOutputStream
();
writeUleb128
(
bytes
,
s
.
length
());
// This isn't MUTF-8, but should be OK.
bytes
.
write
(
s
.
getBytes
(
"UTF-8"
));
bytes
.
write
(
0
);
return
bytes
.
toByteArray
();
}
private
DexCreator
()
{}
}
xposedcompat/src/main/java/de/robv/android/xposed/SELinuxHelper.java
deleted
100644 → 0
View file @
08c68ea5
package
de
.
robv
.
android
.
xposed
;
//import android.os.SELinux;
import
de.robv.android.xposed.services.BaseService
;
import
de.robv.android.xposed.services.DirectAccessService
;
/**
* A helper to work with (or without) SELinux, abstracting much of its big complexity.
*/
public
final
class
SELinuxHelper
{
private
SELinuxHelper
()
{}
/**
* Determines whether SELinux is disabled or enabled.
*
* @return A boolean indicating whether SELinux is enabled.
*/
public
static
boolean
isSELinuxEnabled
()
{
return
sIsSELinuxEnabled
;
}
/**
* Determines whether SELinux is permissive or enforcing.
*
* @return A boolean indicating whether SELinux is enforcing.
*/
// public static boolean isSELinuxEnforced() {
// return sIsSELinuxEnabled && SELinux.isSELinuxEnforced();
// }
/**
* Gets the security context of the current process.
*
* @return A String representing the security context of the current process.
*/
// public static String getContext() {
// return sIsSELinuxEnabled ? SELinux.getContext() : null;
// }
/**
* Retrieve the service to be used when accessing files in {@code /data/data/*}.
*
* <p class="caution"><strong>IMPORTANT:</strong> If you call this from the Zygote process,
* don't re-use the result in different process!
*
* @return An instance of the service.
*/
public
static
BaseService
getAppDataFileService
()
{
if
(
sServiceAppDataFile
!=
null
)
return
sServiceAppDataFile
;
throw
new
UnsupportedOperationException
();
}
// ----------------------------------------------------------------------------
private
static
boolean
sIsSELinuxEnabled
=
false
;
private
static
BaseService
sServiceAppDataFile
=
new
DirectAccessService
();
// ed: initialized directly
/*package*/
static
void
initOnce
()
{
// ed: we assume all selinux policies have been added lively using magiskpolicy
// try {
// sIsSELinuxEnabled = SELinux.isSELinuxEnabled();
// } catch (NoClassDefFoundError ignored) {}
}
/*package*/
static
void
initForProcess
(
String
packageName
)
{
// ed: sServiceAppDataFile has been initialized with default value
// if (sIsSELinuxEnabled) {
// if (packageName == null) { // Zygote
// sServiceAppDataFile = new ZygoteService();
// } else if (packageName.equals("android")) { //system_server
// sServiceAppDataFile = BinderService.getService(BinderService.TARGET_APP);
// } else { // app
// sServiceAppDataFile = new DirectAccessService();
// }
// } else {
// sServiceAppDataFile = new DirectAccessService();
// }
}
}
xposedcompat/src/main/java/de/robv/android/xposed/XSharedPreferences.java
View file @
aa9be549
...
...
@@ -5,20 +5,12 @@ import android.content.Context;
import
android.content.SharedPreferences
;
import
android.os.Environment
;
import
android.preference.PreferenceManager
;
import
android.util.Log
;
import
org.xmlpull.v1.XmlPullParserException
;
import
java.io.File
;
import
java.io.FileNotFoundException
;
import
java.io.IOException
;
import
java.util.HashMap
;
import
java.util.Map
;
import
java.util.Set
;
import
de.robv.android.xposed.services.FileResult
;
/**
* This class is basically the same as SharedPreferencesImpl from AOSP, but
* read-only and without listeners support. Instead, it is made to be
...
...
@@ -77,13 +69,7 @@ public final class XSharedPreferences implements SharedPreferences {
*/
@SuppressLint
(
"SetWorldReadable"
)
public
boolean
makeWorldReadable
()
{
if
(!
SELinuxHelper
.
getAppDataFileService
().
hasDirectFileAccess
())
return
false
;
// It doesn't make much sense to make the file readable if we wouldn't be able to access it anyway.
if
(!
mFile
.
exists
())
// Just in case - the file should never be created if it doesn't exist.
return
false
;
return
mFile
.
setReadable
(
true
,
false
);
return
false
;
}
/**
...
...
@@ -111,45 +97,7 @@ public final class XSharedPreferences implements SharedPreferences {
@SuppressWarnings
({
"rawtypes"
,
"unchecked"
})
private
void
loadFromDiskLocked
()
{
if
(
mLoaded
)
{
return
;
}
Map
map
=
null
;
FileResult
result
=
null
;
try
{
result
=
SELinuxHelper
.
getAppDataFileService
().
getFileInputStream
(
mFilename
,
mFileSize
,
mLastModified
);
if
(
result
.
stream
!=
null
)
{
//map = XmlUtils.readMapXml(result.stream);
result
.
stream
.
close
();
}
else
{
// The file is unchanged, keep the current values
map
=
mMap
;
}
}
catch
(
FileNotFoundException
ignored
)
{
// SharedPreferencesImpl has a canRead() check, so it doesn't log anything in case the file doesn't exist
}
catch
(
IOException
e
)
{
Log
.
w
(
TAG
,
"getSharedPreferences"
,
e
);
}
finally
{
if
(
result
!=
null
&&
result
.
stream
!=
null
)
{
try
{
result
.
stream
.
close
();
}
catch
(
RuntimeException
rethrown
)
{
throw
rethrown
;
}
catch
(
Exception
ignored
)
{
}
}
}
mLoaded
=
true
;
if
(
map
!=
null
)
{
mMap
=
map
;
mLastModified
=
result
.
mtime
;
mFileSize
=
result
.
size
;
}
else
{
mMap
=
new
HashMap
<>();
}
notifyAll
();
}
/**
...
...
@@ -168,16 +116,7 @@ public final class XSharedPreferences implements SharedPreferences {
* <p><strong>Warning:</strong> With enforcing SELinux, this call might be quite expensive.
*/
public
synchronized
boolean
hasFileChanged
()
{
try
{
FileResult
result
=
SELinuxHelper
.
getAppDataFileService
().
statFile
(
mFilename
);
return
mLastModified
!=
result
.
mtime
||
mFileSize
!=
result
.
size
;
}
catch
(
FileNotFoundException
ignored
)
{
// SharedPreferencesImpl doesn't log anything in case the file doesn't exist
return
true
;
}
catch
(
IOException
e
)
{
Log
.
w
(
TAG
,
"hasFileChanged"
,
e
);
return
true
;
}
return
false
;
}
private
void
awaitLoadedLocked
()
{
...
...
xposedcompat/src/main/java/de/robv/android/xposed/XposedBridge.java
View file @
aa9be549
...
...
@@ -3,7 +3,6 @@ package de.robv.android.xposed;
import
android.annotation.SuppressLint
;
import
android.util.Log
;
import
com.swift.sandhook.xposedcompat.methodgen.DynamicBridge
;
import
com.swift.sandhook.xposedcompat.utils.DexLog
;
...
...
@@ -21,7 +20,6 @@ import java.util.HashSet;
import
java.util.Map
;
import
java.util.Set
;
import
de.robv.android.xposed.XC_MethodHook.MethodHookParam
;
import
de.robv.android.xposed.callbacks.XC_InitPackageResources
;
import
de.robv.android.xposed.callbacks.XC_LoadPackage
;
...
...
@@ -50,7 +48,7 @@ public final class XposedBridge {
/*package*/
static
boolean
isZygote
=
true
;
// ed: RuntimeInit.main() tool process not supported yet
private
static
int
runtime
=
2
;
// ed: only support art
private
static
int
runtime
=
2
;
private
static
final
int
RUNTIME_DALVIK
=
1
;
private
static
final
int
RUNTIME_ART
=
2
;
...
...
@@ -74,43 +72,20 @@ public final class XposedBridge {
*/
@SuppressWarnings
(
"deprecation"
)
public
static
void
main
(
String
[]
args
)
{
// ed: moved
}
/** @hide */
// protected static final class ToolEntryPoint {
// protected static void main(String[] args) {
// isZygote = false;
// XposedBridge.main(args);
// }
// }
private
static
void
initXResources
()
throws
IOException
{
// ed: no support for now
}
@SuppressLint
(
"SetWorldReadable"
)
private
static
File
ensureSuperDexFile
(
String
clz
,
Class
<?>
realSuperClz
,
Class
<?>
topClz
)
throws
IOException
{
XposedBridge
.
removeFinalFlagNative
(
realSuperClz
);
File
dexFile
=
DexCreator
.
ensure
(
clz
,
realSuperClz
,
topClz
);
dexFile
.
setReadable
(
true
,
false
);
return
dexFile
;
return
null
;
}
// private static boolean hadInitErrors() {
// // ed: assuming never had errors
// return false;
// }
// private static native int getRuntime();
// /*package*/ static native boolean startsSystemServer();
// /*package*/ static native String getStartClassName();
// /*package*/ native static boolean initXResourcesNative();
/**
* Returns the currently installed version of the Xposed framework.
*/
public
static
int
getXposedVersion
()
{
// ed: fixed value for now
return
90
;
}
...
...
@@ -262,95 +237,6 @@ public final class XposedBridge {
return
unhooks
;
}
/**
* This method is called as a replacement for hooked methods.
*/
private
static
Object
handleHookedMethod
(
Member
method
,
int
originalMethodId
,
Object
additionalInfoObj
,
Object
thisObject
,
Object
[]
args
)
throws
Throwable
{
AdditionalHookInfo
additionalInfo
=
(
AdditionalHookInfo
)
additionalInfoObj
;
if
(
disableHooks
)
{
try
{
return
invokeOriginalMethodNative
(
method
,
originalMethodId
,
additionalInfo
.
parameterTypes
,
additionalInfo
.
returnType
,
thisObject
,
args
);
}
catch
(
InvocationTargetException
e
)
{
throw
e
.
getCause
();
}
}
Object
[]
callbacksSnapshot
=
additionalInfo
.
callbacks
.
getSnapshot
();
final
int
callbacksLength
=
callbacksSnapshot
.
length
;
if
(
callbacksLength
==
0
)
{
try
{
return
invokeOriginalMethodNative
(
method
,
originalMethodId
,
additionalInfo
.
parameterTypes
,
additionalInfo
.
returnType
,
thisObject
,
args
);
}
catch
(
InvocationTargetException
e
)
{
throw
e
.
getCause
();
}
}
MethodHookParam
param
=
new
MethodHookParam
();
param
.
method
=
method
;
param
.
thisObject
=
thisObject
;
param
.
args
=
args
;
// call "before method" callbacks
int
beforeIdx
=
0
;
do
{
try
{
((
XC_MethodHook
)
callbacksSnapshot
[
beforeIdx
]).
beforeHookedMethod
(
param
);
}
catch
(
Throwable
t
)
{
XposedBridge
.
log
(
t
);
// reset result (ignoring what the unexpectedly exiting callback did)
param
.
setResult
(
null
);
param
.
returnEarly
=
false
;
continue
;
}
if
(
param
.
returnEarly
)
{
// skip remaining "before" callbacks and corresponding "after" callbacks
beforeIdx
++;
break
;
}
}
while
(++
beforeIdx
<
callbacksLength
);
// call original method if not requested otherwise
if
(!
param
.
returnEarly
)
{
try
{
param
.
setResult
(
invokeOriginalMethodNative
(
method
,
originalMethodId
,
additionalInfo
.
parameterTypes
,
additionalInfo
.
returnType
,
param
.
thisObject
,
param
.
args
));
}
catch
(
InvocationTargetException
e
)
{
param
.
setThrowable
(
e
.
getCause
());
}
}
// call "after method" callbacks
int
afterIdx
=
beforeIdx
-
1
;
do
{
Object
lastResult
=
param
.
getResult
();
Throwable
lastThrowable
=
param
.
getThrowable
();
try
{
((
XC_MethodHook
)
callbacksSnapshot
[
afterIdx
]).
afterHookedMethod
(
param
);
}
catch
(
Throwable
t
)
{
XposedBridge
.
log
(
t
);
// reset to last result (ignoring what the unexpectedly exiting callback did)
if
(
lastThrowable
==
null
)
param
.
setResult
(
lastResult
);
else
param
.
setThrowable
(
lastThrowable
);
}
}
while
(--
afterIdx
>=
0
);
// return
if
(
param
.
hasThrowable
())
throw
param
.
getThrowable
();
else
return
param
.
getResult
();
}
/**
* Adds a callback to be executed when an app ("Android package") is loaded.
*
...
...
@@ -377,9 +263,6 @@ public final class XposedBridge {
*/
public
static
void
hookInitPackageResources
(
XC_InitPackageResources
callback
)
{
// TODO not supported yet
// synchronized (sInitPackageResourcesCallbacks) {
// sInitPackageResourcesCallbacks.add(callback);
// }
}
/**
...
...
@@ -392,14 +275,6 @@ public final class XposedBridge {
}
private
static
Object
invokeOriginalMethodNative
(
Member
method
,
int
methodId
,
Class
<?>[]
parameterTypes
,
Class
<?>
returnType
,
Object
thisObject
,
Object
[]
args
)
throws
Throwable
{
return
DynamicBridge
.
invokeOriginalMethod
(
method
,
thisObject
,
args
);
}
/**
* Basically the same as {@link Method#invoke}, but calls the original method
* as it was before the interception by Xposed. Also, access permissions are not checked.
...
...
@@ -425,58 +300,6 @@ public final class XposedBridge {
* @throws InvocationTargetException
* if an exception was thrown by the invoked method
*/
public
static
Object
invokeOriginalMethod
(
Member
method
,
Object
thisObject
,
Object
[]
args
)
throws
Throwable
{
if
(
args
==
null
)
{
args
=
EMPTY_ARRAY
;
}
Class
<?>[]
parameterTypes
;
Class
<?>
returnType
;
if
(
runtime
==
RUNTIME_ART
&&
(
method
instanceof
Method
||
method
instanceof
Constructor
))
{
parameterTypes
=
null
;
returnType
=
null
;
}
else
if
(
method
instanceof
Method
)
{
parameterTypes
=
((
Method
)
method
).
getParameterTypes
();
returnType
=
((
Method
)
method
).
getReturnType
();
}
else
if
(
method
instanceof
Constructor
)
{
parameterTypes
=
((
Constructor
<?>)
method
).
getParameterTypes
();
returnType
=
null
;
}
else
{
throw
new
IllegalArgumentException
(
"method must be of type Method or Constructor"
);
}
return
invokeOriginalMethodNative
(
method
,
0
,
parameterTypes
,
returnType
,
thisObject
,
args
);
}
/*package*/
static
void
setObjectClass
(
Object
obj
,
Class
<?>
clazz
)
{
if
(
clazz
.
isAssignableFrom
(
obj
.
getClass
()))
{
throw
new
IllegalArgumentException
(
"Cannot transfer object from "
+
obj
.
getClass
()
+
" to "
+
clazz
);
}
setObjectClassNative
(
obj
,
clazz
);
}
private
static
native
void
setObjectClassNative
(
Object
obj
,
Class
<?>
clazz
);
/*package*/
static
native
void
dumpObjectNative
(
Object
obj
);
/*package*/
static
Object
cloneToSubclass
(
Object
obj
,
Class
<?>
targetClazz
)
{
if
(
obj
==
null
)
return
null
;
if
(!
obj
.
getClass
().
isAssignableFrom
(
targetClazz
))
throw
new
ClassCastException
(
targetClazz
+
" doesn't extend "
+
obj
.
getClass
());
return
cloneToSubclassNative
(
obj
,
targetClazz
);
}
private
static
native
Object
cloneToSubclassNative
(
Object
obj
,
Class
<?>
targetClazz
);
private
static
native
void
removeFinalFlagNative
(
Class
<?>
clazz
);
// /*package*/ static native void closeFilesBeforeForkNative();
// /*package*/ static native void reopenFilesAfterForkNative();
//
// /*package*/ static native void invalidateCallersNative(Member[] methods);
/** @hide */
public
static
final
class
CopyOnWriteSortedSet
<
E
>
{
...
...
xposedcompat/src/main/java/de/robv/android/xposed/XposedInit.java
View file @
aa9be549
package
de
.
robv
.
android
.
xposed
;
import
android.annotation.SuppressLint
;
import
android.os.Build
;
import
android.util.Log
;
import
java.io.BufferedReader
;
...
...
@@ -9,32 +7,20 @@ import java.io.File;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.InputStreamReader
;
import
java.util.HashSet
;
import
java.util.concurrent.atomic.AtomicBoolean
;
import
java.util.zip.ZipEntry
;
import
java.util.zip.ZipFile
;
import
dalvik.system.DexClassLoader
;
import
dalvik.system.DexFile
;
import
de.robv.android.xposed.services.BaseService
;
import
static
de
.
robv
.
android
.
xposed
.
XposedHelpers
.
closeSilently
;
public
final
class
XposedInit
{
private
static
final
String
TAG
=
XposedBridge
.
TAG
;
private
static
boolean
startsSystemServer
=
false
;
private
static
final
String
startClassName
=
""
;
// ed: no support for tool process anymore
public
static
final
String
INSTALLER_PACKAGE_NAME
=
"com.solohsu.android.edxp.manager"
;
public
static
final
String
INSTALLER_LEGACY_PACKAGE_NAME
=
"de.robv.android.xposed.installer"
;
@SuppressLint
(
"SdCardPath"
)
public
static
final
String
INSTALLER_DATA_BASE_DIR
=
Build
.
VERSION
.
SDK_INT
>=
24
?
"/data/user_de/0/"
+
INSTALLER_PACKAGE_NAME
+
"/"
:
"/data/data/"
+
INSTALLER_PACKAGE_NAME
+
"/"
;
private
static
final
String
INSTANT_RUN_CLASS
=
"com.android.tools.fd.runtime.BootstrapApplication"
;
// TODO not supported yet
private
static
boolean
disableResources
=
true
;
private
static
final
String
[]
XRESOURCES_CONFLICTING_PACKAGES
=
{
"com.sygic.aura"
};
private
XposedInit
()
{
}
...
...
@@ -44,27 +30,6 @@ public final class XposedInit {
/**
* Hook some methods which we want to create an easier interface for developers.
*/
/*package*/
// public static void initForZygote(boolean isSystem) throws Throwable {
// if (!bootstrapHooked.compareAndSet(false, true)) {
// return;
// }
// startsSystemServer = isSystem;
// Router.startBootstrapHook(isSystem);
// // MIUI
// if (findFieldIfExists(ZygoteInit.class, "BOOT_START_TIME") != null) {
// setStaticLongField(ZygoteInit.class, "BOOT_START_TIME", XposedBridge.BOOT_START_TIME);
// }
//
// // Samsung
// if (Build.VERSION.SDK_INT >= 24) {
// Class<?> zygote = findClass("com.android.internal.os.Zygote", null);
// try {
// setStaticBooleanField(zygote, "isEnhancedZygoteASLREnabled", false);
// } catch (NoSuchFieldError ignored) {
// }
// }
// }
/*package*/
static
void
hookResources
()
throws
Throwable
{
...
...
@@ -81,32 +46,6 @@ public final class XposedInit {
*/
private
static
volatile
AtomicBoolean
modulesLoaded
=
new
AtomicBoolean
(
false
);
public
static
void
loadModules
()
throws
IOException
{
if
(!
modulesLoaded
.
compareAndSet
(
false
,
true
))
{
return
;
}
final
String
filename
=
INSTALLER_DATA_BASE_DIR
+
"conf/modules.list"
;
BaseService
service
=
SELinuxHelper
.
getAppDataFileService
();
if
(!
service
.
checkFileExists
(
filename
))
{
Log
.
e
(
TAG
,
"Cannot load any modules because "
+
filename
+
" was not found"
);
return
;
}
ClassLoader
topClassLoader
=
XposedBridge
.
BOOTCLASSLOADER
;
ClassLoader
parent
;
while
((
parent
=
topClassLoader
.
getParent
())
!=
null
)
{
topClassLoader
=
parent
;
}
InputStream
stream
=
service
.
getFileInputStream
(
filename
);
BufferedReader
apks
=
new
BufferedReader
(
new
InputStreamReader
(
stream
));
String
apk
;
while
((
apk
=
apks
.
readLine
())
!=
null
)
{
loadModule
(
apk
,
null
,
null
,
topClassLoader
);
}
apks
.
close
();
}
/**
* Load a module from an APK by calling the init(String) method for all classes defined
...
...
@@ -201,17 +140,12 @@ public final class XposedInit {
//so off
if
(
moduleInstance
instanceof
IXposedHookInitPackageResources
)
{
throw
new
UnsupportedOperationException
(
"can not hook resource!"
);
//XposedBridge.hookInitPackageResources(new IXposedHookInitPackageResources.Wrapper((IXposedHookInitPackageResources) moduleInstance));
}
}
else
{
//not support now
//so off
if
(
moduleInstance
instanceof
IXposedHookCmdInit
)
{
throw
new
UnsupportedOperationException
(
"can not hook cmd!"
);
// IXposedHookCmdInit.StartupParam param = new IXposedHookCmdInit.StartupParam();
// param.modulePath = apk;
// param.startClassName = startClassName;
// ((IXposedHookCmdInit) moduleInstance).initCmdApp(param);
}
}
}
catch
(
Throwable
t
)
{
...
...
@@ -225,6 +159,4 @@ public final class XposedInit {
closeSilently
(
zipFile
);
}
}
public
final
static
HashSet
<
String
>
loadedPackagesInProcess
=
new
HashSet
<>(
1
);
}
xposedcompat/src/main/java/de/robv/android/xposed/services/BaseService.java
deleted
100644 → 0
View file @
08c68ea5
package
de
.
robv
.
android
.
xposed
.
services
;
import
java.io.ByteArrayInputStream
;
import
java.io.FileNotFoundException
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
de.robv.android.xposed.SELinuxHelper
;
/**
* General definition of a file access service provided by the Xposed framework.
*
* <p>References to a concrete subclass should generally be retrieved from {@link SELinuxHelper}.
*/
public
abstract
class
BaseService
{
/** Flag for {@link #checkFileAccess}: Read access. */
public
static
final
int
R_OK
=
4
;
/** Flag for {@link #checkFileAccess}: Write access. */
public
static
final
int
W_OK
=
2
;
/** Flag for {@link #checkFileAccess}: Executable access. */
public
static
final
int
X_OK
=
1
;
/** Flag for {@link #checkFileAccess}: File/directory exists. */
public
static
final
int
F_OK
=
0
;
/**
* Checks whether the services accesses files directly (instead of using IPC).
*
* @return {@code true} in case direct access is possible.
*/
public
boolean
hasDirectFileAccess
()
{
return
false
;
}
/**
* Check whether a file is accessible. SELinux might enforce stricter checks.
*
* @param filename The absolute path of the file to check.
* @param mode The mode for POSIX's {@code access()} function.
* @return The result of the {@code access()} function.
*/
public
abstract
boolean
checkFileAccess
(
String
filename
,
int
mode
);
/**
* Check whether a file exists.
*
* @param filename The absolute path of the file to check.
* @return The result of the {@code access()} function.
*/
@SuppressWarnings
(
"BooleanMethodIsAlwaysInverted"
)
public
boolean
checkFileExists
(
String
filename
)
{
return
checkFileAccess
(
filename
,
F_OK
);
}
/**
* Determine the size and modification time of a file.
*
* @param filename The absolute path of the file to check.
* @return A {@link FileResult} object holding the result.
* @throws IOException In case an error occurred while retrieving the information.
*/
public
abstract
FileResult
statFile
(
String
filename
)
throws
IOException
;
/**
* Determine the size time of a file.
*
* @param filename The absolute path of the file to check.
* @return The file size.
* @throws IOException In case an error occurred while retrieving the information.
*/
public
long
getFileSize
(
String
filename
)
throws
IOException
{
return
statFile
(
filename
).
size
;
}
/**
* Determine the size time of a file.
*
* @param filename The absolute path of the file to check.
* @return The file modification time.
* @throws IOException In case an error occurred while retrieving the information.
*/
public
long
getFileModificationTime
(
String
filename
)
throws
IOException
{
return
statFile
(
filename
).
mtime
;
}
/**
* Read a file into memory.
*
* @param filename The absolute path of the file to read.
* @return A {@code byte} array with the file content.
* @throws IOException In case an error occurred while reading the file.
*/
public
abstract
byte
[]
readFile
(
String
filename
)
throws
IOException
;
/**
* Read a file into memory, but only if it has changed since the last time.
*
* @param filename The absolute path of the file to read.
* @param previousSize File size of last read.
* @param previousTime File modification time of last read.
* @return A {@link FileResult} object holding the result.
* <p>The {@link FileResult#content} field might be {@code null} if the file
* is unmodified ({@code previousSize} and {@code previousTime} are still valid).
* @throws IOException In case an error occurred while reading the file.
*/
public
abstract
FileResult
readFile
(
String
filename
,
long
previousSize
,
long
previousTime
)
throws
IOException
;
/**
* Read a file into memory, optionally only if it has changed since the last time.
*
* @param filename The absolute path of the file to read.
* @param offset Number of bytes to skip at the beginning of the file.
* @param length Number of bytes to read (0 means read to end of file).
* @param previousSize Optional: File size of last read.
* @param previousTime Optional: File modification time of last read.
* @return A {@link FileResult} object holding the result.
* <p>The {@link FileResult#content} field might be {@code null} if the file
* is unmodified ({@code previousSize} and {@code previousTime} are still valid).
* @throws IOException In case an error occurred while reading the file.
*/
public
abstract
FileResult
readFile
(
String
filename
,
int
offset
,
int
length
,
long
previousSize
,
long
previousTime
)
throws
IOException
;
/**
* Get a stream to the file content.
* Depending on the service, it may or may not be read completely into memory.
*
* @param filename The absolute path of the file to read.
* @return An {@link InputStream} to the file content.
* @throws IOException In case an error occurred while reading the file.
*/
public
InputStream
getFileInputStream
(
String
filename
)
throws
IOException
{
return
new
ByteArrayInputStream
(
readFile
(
filename
));
}
/**
* Get a stream to the file content, but only if it has changed since the last time.
* Depending on the service, it may or may not be read completely into memory.
*
* @param filename The absolute path of the file to read.
* @param previousSize Optional: File size of last read.
* @param previousTime Optional: File modification time of last read.
* @return A {@link FileResult} object holding the result.
* <p>The {@link FileResult#stream} field might be {@code null} if the file
* is unmodified ({@code previousSize} and {@code previousTime} are still valid).
* @throws IOException In case an error occurred while reading the file.
*/
public
FileResult
getFileInputStream
(
String
filename
,
long
previousSize
,
long
previousTime
)
throws
IOException
{
FileResult
result
=
readFile
(
filename
,
previousSize
,
previousTime
);
if
(
result
.
content
==
null
)
return
result
;
return
new
FileResult
(
new
ByteArrayInputStream
(
result
.
content
),
result
.
size
,
result
.
mtime
);
}
// ----------------------------------------------------------------------------
/*package*/
BaseService
()
{}
/*package*/
static
void
ensureAbsolutePath
(
String
filename
)
{
if
(!
filename
.
startsWith
(
"/"
))
{
throw
new
IllegalArgumentException
(
"Only absolute filenames are allowed: "
+
filename
);
}
}
/*package*/
static
void
throwCommonIOException
(
int
errno
,
String
errorMsg
,
String
filename
,
String
defaultText
)
throws
IOException
{
switch
(
errno
)
{
case
1
:
// EPERM
case
13
:
// EACCES
throw
new
FileNotFoundException
(
errorMsg
!=
null
?
errorMsg
:
"Permission denied: "
+
filename
);
case
2
:
// ENOENT
throw
new
FileNotFoundException
(
errorMsg
!=
null
?
errorMsg
:
"No such file or directory: "
+
filename
);
case
12
:
// ENOMEM
throw
new
OutOfMemoryError
(
errorMsg
);
case
21
:
// EISDIR
throw
new
FileNotFoundException
(
errorMsg
!=
null
?
errorMsg
:
"Is a directory: "
+
filename
);
default
:
throw
new
IOException
(
errorMsg
!=
null
?
errorMsg
:
"Error "
+
errno
+
defaultText
+
filename
);
}
}
}
xposedcompat/src/main/java/de/robv/android/xposed/services/BinderService.java
deleted
100644 → 0
View file @
08c68ea5
package
de
.
robv
.
android
.
xposed
.
services
;
import
android.os.IBinder
;
import
android.os.Parcel
;
import
android.os.RemoteException
;
//import android.os.ServiceManager;
import
java.io.IOException
;
/** @hide */
public
final
class
BinderService
extends
BaseService
{
public
static
final
int
TARGET_APP
=
0
;
public
static
final
int
TARGET_SYSTEM
=
1
;
/**
* Retrieve the binder service running in the specified context.
* @param target Either {@link #TARGET_APP} or {@link #TARGET_SYSTEM}.
* @return A reference to the service.
* @throws IllegalStateException In case the service doesn't exist (should never happen).
*/
public
static
BinderService
getService
(
int
target
)
{
if
(
target
<
0
||
target
>
sServices
.
length
)
{
throw
new
IllegalArgumentException
(
"Invalid service target "
+
target
);
}
synchronized
(
sServices
)
{
if
(
sServices
[
target
]
==
null
)
{
sServices
[
target
]
=
new
BinderService
(
target
);
}
return
sServices
[
target
];
}
}
@Override
public
boolean
checkFileAccess
(
String
filename
,
int
mode
)
{
ensureAbsolutePath
(
filename
);
Parcel
data
=
Parcel
.
obtain
();
Parcel
reply
=
Parcel
.
obtain
();
data
.
writeInterfaceToken
(
INTERFACE_TOKEN
);
data
.
writeString
(
filename
);
data
.
writeInt
(
mode
);
try
{
mRemote
.
transact
(
ACCESS_FILE_TRANSACTION
,
data
,
reply
,
0
);
}
catch
(
RemoteException
e
)
{
data
.
recycle
();
reply
.
recycle
();
return
false
;
}
reply
.
readException
();
int
result
=
reply
.
readInt
();
reply
.
recycle
();
data
.
recycle
();
return
result
==
0
;
}
@Override
public
FileResult
statFile
(
String
filename
)
throws
IOException
{
ensureAbsolutePath
(
filename
);
Parcel
data
=
Parcel
.
obtain
();
Parcel
reply
=
Parcel
.
obtain
();
data
.
writeInterfaceToken
(
INTERFACE_TOKEN
);
data
.
writeString
(
filename
);
try
{
mRemote
.
transact
(
STAT_FILE_TRANSACTION
,
data
,
reply
,
0
);
}
catch
(
RemoteException
e
)
{
data
.
recycle
();
reply
.
recycle
();
throw
new
IOException
(
e
);
}
reply
.
readException
();
int
errno
=
reply
.
readInt
();
if
(
errno
!=
0
)
throwCommonIOException
(
errno
,
null
,
filename
,
" while retrieving attributes for "
);
long
size
=
reply
.
readLong
();
long
time
=
reply
.
readLong
();
reply
.
recycle
();
data
.
recycle
();
return
new
FileResult
(
size
,
time
);
}
@Override
public
byte
[]
readFile
(
String
filename
)
throws
IOException
{
return
readFile
(
filename
,
0
,
0
,
0
,
0
).
content
;
}
@Override
public
FileResult
readFile
(
String
filename
,
long
previousSize
,
long
previousTime
)
throws
IOException
{
return
readFile
(
filename
,
0
,
0
,
previousSize
,
previousTime
);
}
@Override
public
FileResult
readFile
(
String
filename
,
int
offset
,
int
length
,
long
previousSize
,
long
previousTime
)
throws
IOException
{
ensureAbsolutePath
(
filename
);
Parcel
data
=
Parcel
.
obtain
();
Parcel
reply
=
Parcel
.
obtain
();
data
.
writeInterfaceToken
(
INTERFACE_TOKEN
);
data
.
writeString
(
filename
);
data
.
writeInt
(
offset
);
data
.
writeInt
(
length
);
data
.
writeLong
(
previousSize
);
data
.
writeLong
(
previousTime
);
try
{
mRemote
.
transact
(
READ_FILE_TRANSACTION
,
data
,
reply
,
0
);
}
catch
(
RemoteException
e
)
{
data
.
recycle
();
reply
.
recycle
();
throw
new
IOException
(
e
);
}
reply
.
readException
();
int
errno
=
reply
.
readInt
();
String
errorMsg
=
reply
.
readString
();
long
size
=
reply
.
readLong
();
long
time
=
reply
.
readLong
();
byte
[]
content
=
reply
.
createByteArray
();
reply
.
recycle
();
data
.
recycle
();
switch
(
errno
)
{
case
0
:
return
new
FileResult
(
content
,
size
,
time
);
case
22
:
// EINVAL
if
(
errorMsg
!=
null
)
{
IllegalArgumentException
iae
=
new
IllegalArgumentException
(
errorMsg
);
if
(
offset
==
0
&&
length
==
0
)
throw
new
IOException
(
iae
);
else
throw
iae
;
}
else
{
throw
new
IllegalArgumentException
(
"Offset "
+
offset
+
" / Length "
+
length
+
" is out of range for "
+
filename
+
" with size "
+
size
);
}
default
:
throwCommonIOException
(
errno
,
errorMsg
,
filename
,
" while reading "
);
throw
new
IllegalStateException
();
// not reached
}
}
// ----------------------------------------------------------------------------
private
static
final
String
INTERFACE_TOKEN
=
"de.robv.android.xposed.IXposedService"
;
private
static
final
int
ACCESS_FILE_TRANSACTION
=
IBinder
.
FIRST_CALL_TRANSACTION
+
2
;
private
static
final
int
STAT_FILE_TRANSACTION
=
IBinder
.
FIRST_CALL_TRANSACTION
+
3
;
private
static
final
int
READ_FILE_TRANSACTION
=
IBinder
.
FIRST_CALL_TRANSACTION
+
4
;
private
static
final
String
[]
SERVICE_NAMES
=
{
"user.xposed.app"
,
"user.xposed.system"
};
private
static
final
BinderService
[]
sServices
=
new
BinderService
[
2
];
private
final
IBinder
mRemote
;
private
BinderService
(
int
target
)
{
IBinder
binder
=
null
;
//ServiceManager.getService(SERVICE_NAMES[target]);
if
(
binder
==
null
)
throw
new
IllegalStateException
(
"Service "
+
SERVICE_NAMES
[
target
]
+
" does not exist"
);
this
.
mRemote
=
binder
;
}
}
xposedcompat/src/main/java/de/robv/android/xposed/services/DirectAccessService.java
deleted
100644 → 0
View file @
08c68ea5
package
de
.
robv
.
android
.
xposed
.
services
;
import
java.io.BufferedInputStream
;
import
java.io.File
;
import
java.io.FileInputStream
;
import
java.io.IOException
;
import
java.io.InputStream
;
/** @hide */
public
final
class
DirectAccessService
extends
BaseService
{
@Override
public
boolean
hasDirectFileAccess
()
{
return
true
;
}
@SuppressWarnings
(
"RedundantIfStatement"
)
@Override
public
boolean
checkFileAccess
(
String
filename
,
int
mode
)
{
File
file
=
new
File
(
filename
);
if
(
mode
==
F_OK
&&
!
file
.
exists
())
return
false
;
if
((
mode
&
R_OK
)
!=
0
&&
!
file
.
canRead
())
return
false
;
if
((
mode
&
W_OK
)
!=
0
&&
!
file
.
canWrite
())
return
false
;
if
((
mode
&
X_OK
)
!=
0
&&
!
file
.
canExecute
())
return
false
;
return
true
;
}
@Override
public
boolean
checkFileExists
(
String
filename
)
{
return
new
File
(
filename
).
exists
();
}
@Override
public
FileResult
statFile
(
String
filename
)
throws
IOException
{
File
file
=
new
File
(
filename
);
return
new
FileResult
(
file
.
length
(),
file
.
lastModified
());
}
@Override
public
byte
[]
readFile
(
String
filename
)
throws
IOException
{
File
file
=
new
File
(
filename
);
byte
content
[]
=
new
byte
[(
int
)
file
.
length
()];
FileInputStream
fis
=
new
FileInputStream
(
file
);
fis
.
read
(
content
);
fis
.
close
();
return
content
;
}
@Override
public
FileResult
readFile
(
String
filename
,
long
previousSize
,
long
previousTime
)
throws
IOException
{
File
file
=
new
File
(
filename
);
long
size
=
file
.
length
();
long
time
=
file
.
lastModified
();
if
(
previousSize
==
size
&&
previousTime
==
time
)
return
new
FileResult
(
size
,
time
);
return
new
FileResult
(
readFile
(
filename
),
size
,
time
);
}
@Override
public
FileResult
readFile
(
String
filename
,
int
offset
,
int
length
,
long
previousSize
,
long
previousTime
)
throws
IOException
{
File
file
=
new
File
(
filename
);
long
size
=
file
.
length
();
long
time
=
file
.
lastModified
();
if
(
previousSize
==
size
&&
previousTime
==
time
)
return
new
FileResult
(
size
,
time
);
// Shortcut for the simple case
if
(
offset
<=
0
&&
length
<=
0
)
return
new
FileResult
(
readFile
(
filename
),
size
,
time
);
// Check range
if
(
offset
>
0
&&
offset
>=
size
)
{
throw
new
IllegalArgumentException
(
"Offset "
+
offset
+
" is out of range for "
+
filename
);
}
else
if
(
offset
<
0
)
{
offset
=
0
;
}
if
(
length
>
0
&&
(
offset
+
length
)
>
size
)
{
throw
new
IllegalArgumentException
(
"Length "
+
length
+
" is out of range for "
+
filename
);
}
else
if
(
length
<=
0
)
{
length
=
(
int
)
(
size
-
offset
);
}
byte
content
[]
=
new
byte
[
length
];
FileInputStream
fis
=
new
FileInputStream
(
file
);
fis
.
skip
(
offset
);
fis
.
read
(
content
);
fis
.
close
();
return
new
FileResult
(
content
,
size
,
time
);
}
/**
* {@inheritDoc}
* <p>This implementation returns a BufferedInputStream instead of loading the file into memory.
*/
@Override
public
InputStream
getFileInputStream
(
String
filename
)
throws
IOException
{
return
new
BufferedInputStream
(
new
FileInputStream
(
filename
),
16
*
1024
);
}
/**
* {@inheritDoc}
* <p>This implementation returns a BufferedInputStream instead of loading the file into memory.
*/
@Override
public
FileResult
getFileInputStream
(
String
filename
,
long
previousSize
,
long
previousTime
)
throws
IOException
{
File
file
=
new
File
(
filename
);
long
size
=
file
.
length
();
long
time
=
file
.
lastModified
();
if
(
previousSize
==
size
&&
previousTime
==
time
)
return
new
FileResult
(
size
,
time
);
return
new
FileResult
(
new
BufferedInputStream
(
new
FileInputStream
(
filename
),
16
*
1024
),
size
,
time
);
}
}
xposedcompat/src/main/java/de/robv/android/xposed/services/FileResult.java
deleted
100644 → 0
View file @
08c68ea5
package
de
.
robv
.
android
.
xposed
.
services
;
import
java.io.InputStream
;
/**
* Holder for the result of a {@link BaseService#readFile} or {@link BaseService#statFile} call.
*/
public
final
class
FileResult
{
/** File content, might be {@code null} if the file wasn't read. */
public
final
byte
[]
content
;
/** File input stream, might be {@code null} if the file wasn't read. */
public
final
InputStream
stream
;
/** File size. */
public
final
long
size
;
/** File last modification time. */
public
final
long
mtime
;
/*package*/
FileResult
(
long
size
,
long
mtime
)
{
this
.
content
=
null
;
this
.
stream
=
null
;
this
.
size
=
size
;
this
.
mtime
=
mtime
;
}
/*package*/
FileResult
(
byte
[]
content
,
long
size
,
long
mtime
)
{
this
.
content
=
content
;
this
.
stream
=
null
;
this
.
size
=
size
;
this
.
mtime
=
mtime
;
}
/*package*/
FileResult
(
InputStream
stream
,
long
size
,
long
mtime
)
{
this
.
content
=
null
;
this
.
stream
=
stream
;
this
.
size
=
size
;
this
.
mtime
=
mtime
;
}
/** @hide */
@Override
public
String
toString
()
{
StringBuilder
sb
=
new
StringBuilder
(
"{"
);
if
(
content
!=
null
)
{
sb
.
append
(
"content.length: "
);
sb
.
append
(
content
.
length
);
sb
.
append
(
", "
);
}
if
(
stream
!=
null
)
{
sb
.
append
(
"stream: "
);
sb
.
append
(
stream
.
toString
());
sb
.
append
(
", "
);
}
sb
.
append
(
"size: "
);
sb
.
append
(
size
);
sb
.
append
(
", mtime: "
);
sb
.
append
(
mtime
);
sb
.
append
(
"}"
);
return
sb
.
toString
();
}
}
xposedcompat/src/main/java/de/robv/android/xposed/services/ZygoteService.java
deleted
100644 → 0
View file @
08c68ea5
package
de
.
robv
.
android
.
xposed
.
services
;
import
java.io.IOException
;
import
java.util.Arrays
;
/** @hide */
@SuppressWarnings
(
"JniMissingFunction"
)
public
final
class
ZygoteService
extends
BaseService
{
@Override
public
native
boolean
checkFileAccess
(
String
filename
,
int
mode
);
@Override
public
native
FileResult
statFile
(
String
filename
)
throws
IOException
;
@Override
public
native
byte
[]
readFile
(
String
filename
)
throws
IOException
;
@Override
// Just for completeness, we don't expect this to be called often in Zygote.
public
FileResult
readFile
(
String
filename
,
long
previousSize
,
long
previousTime
)
throws
IOException
{
FileResult
stat
=
statFile
(
filename
);
if
(
previousSize
==
stat
.
size
&&
previousTime
==
stat
.
mtime
)
return
stat
;
return
new
FileResult
(
readFile
(
filename
),
stat
.
size
,
stat
.
mtime
);
}
@Override
// Just for completeness, we don't expect this to be called often in Zygote.
public
FileResult
readFile
(
String
filename
,
int
offset
,
int
length
,
long
previousSize
,
long
previousTime
)
throws
IOException
{
FileResult
stat
=
statFile
(
filename
);
if
(
previousSize
==
stat
.
size
&&
previousTime
==
stat
.
mtime
)
return
stat
;
// Shortcut for the simple case
if
(
offset
<=
0
&&
length
<=
0
)
return
new
FileResult
(
readFile
(
filename
),
stat
.
size
,
stat
.
mtime
);
// Check range
if
(
offset
>
0
&&
offset
>=
stat
.
size
)
{
throw
new
IllegalArgumentException
(
"offset "
+
offset
+
" >= size "
+
stat
.
size
+
" for "
+
filename
);
}
else
if
(
offset
<
0
)
{
offset
=
0
;
}
if
(
length
>
0
&&
(
offset
+
length
)
>
stat
.
size
)
{
throw
new
IllegalArgumentException
(
"offset "
+
offset
+
" + length "
+
length
+
" > size "
+
stat
.
size
+
" for "
+
filename
);
}
else
if
(
length
<=
0
)
{
length
=
(
int
)
(
stat
.
size
-
offset
);
}
byte
[]
content
=
readFile
(
filename
);
return
new
FileResult
(
Arrays
.
copyOfRange
(
content
,
offset
,
offset
+
length
),
stat
.
size
,
stat
.
mtime
);
}
}
xposedcompat/src/main/java/de/robv/android/xposed/services/package-info.java
deleted
100644 → 0
View file @
08c68ea5
/**
* Contains file access services provided by the Xposed framework.
*/
package
de
.
robv
.
android
.
xposed
.
services
;
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment