Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Contribute to GitLab
Sign in / Register
Toggle navigation
M
Magisk
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
Magisk
Commits
33b7ab59
Commit
33b7ab59
authored
Aug 04, 2019
by
topjohnwu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Migrate PatchAPK to Kotlin
parent
8706d834
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
156 additions
and
173 deletions
+156
-173
App.kt
app/src/main/java/com/topjohnwu/magisk/App.kt
+0
-7
Config.kt
app/src/main/java/com/topjohnwu/magisk/Config.kt
+1
-3
DBConfig.kt
...ain/java/com/topjohnwu/magisk/data/repository/DBConfig.kt
+12
-6
SettingsFragment.kt
...java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt
+1
-1
PatchAPK.java
app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.java
+0
-152
PatchAPK.kt
app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt
+142
-0
Notifications.java
...rc/main/java/com/topjohnwu/magisk/view/Notifications.java
+0
-4
No files found.
app/src/main/java/com/topjohnwu/magisk/App.kt
View file @
33b7ab59
...
...
@@ -4,7 +4,6 @@ import android.annotation.SuppressLint
import
android.app.Application
import
android.content.Context
import
android.content.res.Configuration
import
android.os.AsyncTask
import
android.os.Build
import
androidx.appcompat.app.AppCompatDelegate
import
androidx.multidex.MultiDex
...
...
@@ -23,7 +22,6 @@ import com.topjohnwu.superuser.Shell
import
org.koin.android.ext.koin.androidContext
import
org.koin.core.context.startKoin
import
timber.log.Timber
import
java.util.concurrent.ThreadPoolExecutor
open
class
App
:
Application
()
{
...
...
@@ -68,17 +66,12 @@ open class App : Application() {
@JvmStatic
lateinit
var
self
:
App
@Deprecated
(
"Use Rx or similar"
)
@JvmField
var
THREAD_POOL
:
ThreadPoolExecutor
init
{
AppCompatDelegate
.
setCompatVectorFromResourcesEnabled
(
true
)
Shell
.
Config
.
setFlags
(
Shell
.
FLAG_MOUNT_MASTER
or
Shell
.
FLAG_USE_MAGISK_BUSYBOX
)
Shell
.
Config
.
verboseLogging
(
BuildConfig
.
DEBUG
)
Shell
.
Config
.
addInitializers
(
RootUtils
::
class
.
java
)
Shell
.
Config
.
setTimeout
(
2
)
THREAD_POOL
=
AsyncTask
.
THREAD_POOL_EXECUTOR
as
ThreadPoolExecutor
Room
.
setFactory
{
when
(
it
)
{
WorkDatabase
::
class
.
java
->
WorkDatabase_Impl
()
...
...
app/src/main/java/com/topjohnwu/magisk/Config.kt
View file @
33b7ab59
...
...
@@ -125,8 +125,7 @@ object Config : PreferenceModel, DBConfig {
var
suMntNamespaceMode
by
dbSettings
(
Key
.
SU_MNT_NS
,
Value
.
NAMESPACE_MODE_REQUESTER
)
var
suMultiuserMode
by
dbSettings
(
Key
.
SU_MULTIUSER_MODE
,
Value
.
MULTIUSER_MODE_OWNER_ONLY
)
var
suFingerprint
by
dbSettings
(
Key
.
SU_FINGERPRINT
,
false
)
@JvmStatic
var
suManager
by
dbStrings
(
Key
.
SU_MANAGER
,
""
)
var
suManager
by
dbStrings
(
Key
.
SU_MANAGER
,
""
,
true
)
// Always return a path in external storage where we can write
val
downloadDirectory
get
()
=
...
...
@@ -199,7 +198,6 @@ object Config : PreferenceModel, DBConfig {
}
}
@JvmStatic
fun
export
()
{
// Flush prefs to disk
prefs
.
edit
().
apply
()
...
...
app/src/main/java/com/topjohnwu/magisk/data/repository/DBConfig.kt
View file @
33b7ab59
...
...
@@ -23,8 +23,9 @@ interface DBConfig {
fun
dbStrings
(
name
:
String
,
default
:
String
)
=
DBStringsValue
(
name
,
default
)
default
:
String
,
sync
:
Boolean
=
false
)
=
DBStringsValue
(
name
,
default
,
sync
)
}
...
...
@@ -70,7 +71,8 @@ class DBBoolSettings(
class
DBStringsValue
(
private
val
name
:
String
,
private
val
default
:
String
private
val
default
:
String
,
private
val
sync
:
Boolean
)
:
ReadWriteProperty
<
DBConfig
,
String
>
{
private
var
value
:
String
?
=
null
...
...
@@ -88,8 +90,12 @@ class DBStringsValue(
synchronized
(
this
)
{
this
.
value
=
value
}
thisRef
.
stringDao
.
put
(
getKey
(
property
),
value
)
.
subscribeOn
(
Schedulers
.
io
())
.
subscribe
()
if
(
sync
)
{
thisRef
.
stringDao
.
put
(
getKey
(
property
),
value
).
blockingAwait
()
}
else
{
thisRef
.
stringDao
.
put
(
getKey
(
property
),
value
)
.
subscribeOn
(
Schedulers
.
io
())
.
subscribe
()
}
}
}
app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsFragment.kt
View file @
33b7ab59
...
...
@@ -73,7 +73,7 @@ class SettingsFragment : BasePreferenceFragment() {
val
suCategory
=
findPreference
(
"superuser"
)
as
PreferenceCategory
val
hideManager
=
findPreference
(
"hide"
)
hideManager
.
setOnPreferenceClickListener
{
PatchAPK
.
hideManager
()
PatchAPK
.
hideManager
(
requireContext
()
)
true
}
val
restoreManager
=
findPreference
(
"restore"
)
...
...
app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.java
deleted
100644 → 0
View file @
8706d834
package
com
.
topjohnwu
.
magisk
.
utils
;
import
android.content.ComponentName
;
import
android.widget.Toast
;
import
androidx.core.app.NotificationCompat
;
import
com.topjohnwu.magisk.App
;
import
com.topjohnwu.magisk.BuildConfig
;
import
com.topjohnwu.magisk.ClassMap
;
import
com.topjohnwu.magisk.Config
;
import
com.topjohnwu.magisk.Const
;
import
com.topjohnwu.magisk.R
;
import
com.topjohnwu.magisk.ui.SplashActivity
;
import
com.topjohnwu.magisk.view.Notifications
;
import
com.topjohnwu.signing.JarMap
;
import
com.topjohnwu.signing.SignAPK
;
import
com.topjohnwu.superuser.Shell
;
import
java.io.BufferedOutputStream
;
import
java.io.File
;
import
java.io.FileOutputStream
;
import
java.nio.ByteBuffer
;
import
java.nio.ByteOrder
;
import
java.nio.CharBuffer
;
import
java.nio.IntBuffer
;
import
java.security.SecureRandom
;
import
java.util.ArrayList
;
import
java.util.List
;
import
java.util.jar.JarEntry
;
public
class
PatchAPK
{
public
static
final
String
LOWERALPHA
=
"abcdefghijklmnopqrstuvwxyz"
;
public
static
final
String
UPPERALPHA
=
LOWERALPHA
.
toUpperCase
();
public
static
final
String
ALPHA
=
LOWERALPHA
+
UPPERALPHA
;
public
static
final
String
DIGITS
=
"0123456789"
;
public
static
final
String
ALPHANUM
=
ALPHA
+
DIGITS
;
public
static
final
String
ALPHANUMDOTS
=
ALPHANUM
+
"............"
;
private
static
String
genPackageName
(
String
prefix
,
int
length
)
{
StringBuilder
builder
=
new
StringBuilder
(
length
);
builder
.
append
(
prefix
);
length
-=
prefix
.
length
();
SecureRandom
random
=
new
SecureRandom
();
char
next
,
prev
=
prefix
.
charAt
(
prefix
.
length
()
-
1
);
for
(
int
i
=
0
;
i
<
length
;
++
i
)
{
if
(
prev
==
'.'
||
i
==
length
-
1
)
{
next
=
ALPHA
.
charAt
(
random
.
nextInt
(
ALPHA
.
length
()));
}
else
{
next
=
ALPHANUMDOTS
.
charAt
(
random
.
nextInt
(
ALPHANUMDOTS
.
length
()));
}
builder
.
append
(
next
);
prev
=
next
;
}
return
builder
.
toString
();
}
private
static
boolean
findAndPatch
(
byte
[]
xml
,
String
from
,
String
to
)
{
if
(
from
.
length
()
!=
to
.
length
())
return
false
;
CharBuffer
buf
=
ByteBuffer
.
wrap
(
xml
).
order
(
ByteOrder
.
LITTLE_ENDIAN
).
asCharBuffer
();
List
<
Integer
>
offList
=
new
ArrayList
<>();
for
(
int
i
=
0
;
i
<
buf
.
length
()
-
from
.
length
();
++
i
)
{
boolean
match
=
true
;
for
(
int
j
=
0
;
j
<
from
.
length
();
++
j
)
{
if
(
buf
.
get
(
i
+
j
)
!=
from
.
charAt
(
j
))
{
match
=
false
;
break
;
}
}
if
(
match
)
{
offList
.
add
(
i
);
i
+=
from
.
length
();
}
}
if
(
offList
.
isEmpty
())
return
false
;
for
(
int
off
:
offList
)
{
buf
.
position
(
off
);
buf
.
put
(
to
);
}
return
true
;
}
private
static
boolean
findAndPatch
(
byte
[]
xml
,
int
a
,
int
b
)
{
IntBuffer
buf
=
ByteBuffer
.
wrap
(
xml
).
order
(
ByteOrder
.
LITTLE_ENDIAN
).
asIntBuffer
();
int
len
=
xml
.
length
/
4
;
for
(
int
i
=
0
;
i
<
len
;
++
i
)
{
if
(
buf
.
get
(
i
)
==
a
)
{
buf
.
put
(
i
,
b
);
return
true
;
}
}
return
false
;
}
private
static
boolean
patchAndHide
()
{
App
app
=
App
.
self
;
// Generate a new app with random package name
File
repack
=
new
File
(
app
.
getFilesDir
(),
"patched.apk"
);
String
pkg
=
genPackageName
(
"com."
,
BuildConfig
.
APPLICATION_ID
.
length
());
if
(!
patch
(
app
.
getPackageCodePath
(),
repack
.
getPath
(),
pkg
))
return
false
;
// Install the application
repack
.
setReadable
(
true
,
false
);
if
(!
Shell
.
su
(
"pm install "
+
repack
).
exec
().
isSuccess
())
return
false
;
Config
.
setSuManager
(
pkg
);
Config
.
export
();
RootUtils
.
rmAndLaunch
(
BuildConfig
.
APPLICATION_ID
,
new
ComponentName
(
pkg
,
ClassMap
.
get
(
SplashActivity
.
class
).
getName
()));
return
true
;
}
public
static
boolean
patch
(
String
in
,
String
out
,
String
pkg
)
{
try
{
JarMap
jar
=
new
JarMap
(
in
);
JarEntry
je
=
jar
.
getJarEntry
(
Const
.
ANDROID_MANIFEST
);
byte
[]
xml
=
jar
.
getRawData
(
je
);
if
(!
findAndPatch
(
xml
,
BuildConfig
.
APPLICATION_ID
,
pkg
)
||
!
findAndPatch
(
xml
,
R
.
string
.
app_name
,
R
.
string
.
re_app_name
))
return
false
;
// Write in changes
jar
.
getOutputStream
(
je
).
write
(
xml
);
SignAPK
.
sign
(
jar
,
new
BufferedOutputStream
(
new
FileOutputStream
(
out
)));
}
catch
(
Exception
e
)
{
e
.
printStackTrace
();
return
false
;
}
return
true
;
}
public
static
void
hideManager
()
{
App
.
THREAD_POOL
.
execute
(()
->
{
App
app
=
App
.
self
;
NotificationCompat
.
Builder
progress
=
Notifications
.
progress
(
app
.
getString
(
R
.
string
.
hide_manager_title
));
Notifications
.
mgr
.
notify
(
Const
.
ID
.
HIDE_MANAGER_NOTIFICATION_ID
,
progress
.
build
());
if
(!
patchAndHide
())
Utils
.
INSTANCE
.
toast
(
R
.
string
.
hide_manager_fail_toast
,
Toast
.
LENGTH_LONG
);
Notifications
.
mgr
.
cancel
(
Const
.
ID
.
HIDE_MANAGER_NOTIFICATION_ID
);
});
}
}
app/src/main/java/com/topjohnwu/magisk/utils/PatchAPK.kt
0 → 100644
View file @
33b7ab59
package
com.topjohnwu.magisk.utils
import
android.content.ComponentName
import
android.content.Context
import
android.widget.Toast
import
com.skoumal.teanity.extensions.subscribeK
import
com.topjohnwu.magisk.*
import
com.topjohnwu.magisk.ui.SplashActivity
import
com.topjohnwu.magisk.view.Notifications
import
com.topjohnwu.signing.JarMap
import
com.topjohnwu.signing.SignAPK
import
com.topjohnwu.superuser.Shell
import
io.reactivex.Completable
import
timber.log.Timber
import
java.io.File
import
java.io.FileOutputStream
import
java.nio.ByteBuffer
import
java.nio.ByteOrder
import
java.security.SecureRandom
object
PatchAPK
{
private
const
val
LOWERALPHA
=
"abcdefghijklmnopqrstuvwxyz"
private
val
UPPERALPHA
=
LOWERALPHA
.
toUpperCase
()
private
val
ALPHA
=
LOWERALPHA
+
UPPERALPHA
private
const
val
DIGITS
=
"0123456789"
private
val
ALPHANUM
=
ALPHA
+
DIGITS
private
val
ALPHANUMDOTS
=
"$ALPHANUM............"
private
fun
genPackageName
(
prefix
:
String
,
length
:
Int
):
String
{
val
builder
=
StringBuilder
(
length
)
builder
.
append
(
prefix
)
val
len
=
length
-
prefix
.
length
val
random
=
SecureRandom
()
var
next
:
Char
var
prev
=
prefix
[
prefix
.
length
-
1
]
for
(
i
in
0
until
len
)
{
next
=
if
(
prev
==
'.'
||
i
==
len
-
1
)
{
ALPHA
[
random
.
nextInt
(
ALPHA
.
length
)]
}
else
{
ALPHANUMDOTS
[
random
.
nextInt
(
ALPHANUMDOTS
.
length
)]
}
builder
.
append
(
next
)
prev
=
next
}
return
builder
.
toString
()
}
private
fun
findAndPatch
(
xml
:
ByteArray
,
from
:
String
,
to
:
String
):
Boolean
{
if
(
from
.
length
!=
to
.
length
)
return
false
val
buf
=
ByteBuffer
.
wrap
(
xml
).
order
(
ByteOrder
.
LITTLE_ENDIAN
).
asCharBuffer
()
val
offList
=
mutableListOf
<
Int
>()
var
i
=
0
while
(
i
<
buf
.
length
-
from
.
length
)
{
var
match
=
true
for
(
j
in
0
until
from
.
length
)
{
if
(
buf
.
get
(
i
+
j
)
!=
from
[
j
])
{
match
=
false
break
}
}
if
(
match
)
{
offList
.
add
(
i
)
i
+=
from
.
length
}
++
i
}
if
(
offList
.
isEmpty
())
return
false
for
(
off
in
offList
)
{
buf
.
position
(
off
)
buf
.
put
(
to
)
}
return
true
}
private
fun
findAndPatch
(
xml
:
ByteArray
,
a
:
Int
,
b
:
Int
):
Boolean
{
val
buf
=
ByteBuffer
.
wrap
(
xml
).
order
(
ByteOrder
.
LITTLE_ENDIAN
).
asIntBuffer
()
val
len
=
xml
.
size
/
4
for
(
i
in
0
until
len
)
{
if
(
buf
.
get
(
i
)
==
a
)
{
buf
.
put
(
i
,
b
)
return
true
}
}
return
false
}
private
fun
patchAndHide
(
context
:
Context
):
Boolean
{
// Generate a new app with random package name
val
repack
=
File
(
context
.
filesDir
,
"patched.apk"
)
val
pkg
=
genPackageName
(
"com."
,
BuildConfig
.
APPLICATION_ID
.
length
)
if
(!
patch
(
context
.
packageCodePath
,
repack
.
path
,
pkg
))
return
false
// Install the application
repack
.
setReadable
(
true
,
false
)
if
(!
Shell
.
su
(
"pm install $repack"
).
exec
().
isSuccess
)
return
false
Config
.
suManager
=
pkg
Config
.
export
()
RootUtils
.
rmAndLaunch
(
BuildConfig
.
APPLICATION_ID
,
ComponentName
(
pkg
,
ClassMap
.
get
<
Class
<*>>(
SplashActivity
::
class
.
java
).
name
))
return
true
}
@JvmStatic
fun
patch
(
apk
:
String
,
out
:
String
,
pkg
:
String
):
Boolean
{
try
{
val
jar
=
JarMap
(
apk
)
val
je
=
jar
.
getJarEntry
(
Const
.
ANDROID_MANIFEST
)
val
xml
=
jar
.
getRawData
(
je
)
if
(!
findAndPatch
(
xml
,
BuildConfig
.
APPLICATION_ID
,
pkg
)
||
!
findAndPatch
(
xml
,
R
.
string
.
app_name
,
R
.
string
.
re_app_name
))
return
false
// Write apk changes
jar
.
getOutputStream
(
je
).
write
(
xml
)
SignAPK
.
sign
(
jar
,
FileOutputStream
(
out
).
buffered
())
}
catch
(
e
:
Exception
)
{
Timber
.
e
(
e
)
return
false
}
return
true
}
fun
hideManager
(
context
:
Context
)
{
Completable
.
fromAction
{
val
progress
=
Notifications
.
progress
(
context
,
context
.
getString
(
R
.
string
.
hide_manager_title
))
Notifications
.
mgr
.
notify
(
Const
.
ID
.
HIDE_MANAGER_NOTIFICATION_ID
,
progress
.
build
())
if
(!
patchAndHide
(
context
))
Utils
.
toast
(
R
.
string
.
hide_manager_fail_toast
,
Toast
.
LENGTH_LONG
)
Notifications
.
mgr
.
cancel
(
Const
.
ID
.
HIDE_MANAGER_NOTIFICATION_ID
)
}.
subscribeK
()
}
}
app/src/main/java/com/topjohnwu/magisk/view/Notifications.java
View file @
33b7ab59
...
...
@@ -97,10 +97,6 @@ public class Notifications {
mgr
.
notify
(
Const
.
ID
.
DTBO_NOTIFICATION_ID
,
builder
.
build
());
}
public
static
NotificationCompat
.
Builder
progress
(
CharSequence
title
)
{
return
progress
(
App
.
self
,
title
);
}
public
static
NotificationCompat
.
Builder
progress
(
Context
context
,
CharSequence
title
)
{
NotificationCompat
.
Builder
builder
=
new
NotificationCompat
.
Builder
(
context
,
Const
.
ID
.
PROGRESS_NOTIFICATION_CHANNEL
);
builder
.
setPriority
(
NotificationCompat
.
PRIORITY_LOW
)
...
...
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