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
baa19f0c
Unverified
Commit
baa19f0c
authored
Dec 14, 2021
by
南宫雪珊
Committed by
GitHub
Dec 14, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Rewrite app installation
Fix #4960
parent
5a49bd3a
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
10 changed files
with
161 additions
and
396 deletions
+161
-396
AndroidManifest.xml
app/shared/src/main/AndroidManifest.xml
+1
-0
FileProvider.java
...ared/src/main/java/com/topjohnwu/magisk/FileProvider.java
+0
-303
APKInstall.java
.../src/main/java/com/topjohnwu/magisk/utils/APKInstall.java
+97
-27
Provider.kt
app/src/main/java/com/topjohnwu/magisk/core/Provider.kt
+12
-3
Subject.kt
...c/main/java/com/topjohnwu/magisk/core/download/Subject.kt
+6
-2
HideAPK.kt
app/src/main/java/com/topjohnwu/magisk/core/tasks/HideAPK.kt
+27
-41
manager.sh
app/src/main/res/raw/manager.sh
+3
-1
Codegen.kt
buildSrc/src/main/java/Codegen.kt
+1
-1
proguard-rules.pro
stub/proguard-rules.pro
+0
-1
DownloadActivity.java
.../src/main/java/com/topjohnwu/magisk/DownloadActivity.java
+14
-17
No files found.
app/shared/src/main/AndroidManifest.xml
View file @
baa19f0c
...
...
@@ -8,6 +8,7 @@
<uses-permission
android:name=
"android.permission.FOREGROUND_SERVICE"
/>
<uses-permission
android:name=
"android.permission.REQUEST_INSTALL_PACKAGES"
/>
<uses-permission
android:name=
"android.permission.HIDE_OVERLAY_WINDOWS"
/>
<uses-permission
android:name=
"android.permission.UPDATE_PACKAGES_WITHOUT_USER_ACTION"
/>
<uses-permission
android:name=
"android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion=
"29"
...
...
app/shared/src/main/java/com/topjohnwu/magisk/FileProvider.java
deleted
100644 → 0
View file @
5a49bd3a
This diff is collapsed.
Click to expand it.
app/shared/src/main/java/com/topjohnwu/magisk/utils/APKInstall.java
View file @
baa19f0c
package
com
.
topjohnwu
.
magisk
.
utils
;
import
android.app.Activity
;
import
static
android
.
content
.
pm
.
PackageInstaller
.
EXTRA_STATUS
;
import
static
android
.
content
.
pm
.
PackageInstaller
.
STATUS_FAILURE_INVALID
;
import
static
android
.
content
.
pm
.
PackageInstaller
.
STATUS_PENDING_USER_ACTION
;
import
static
android
.
content
.
pm
.
PackageInstaller
.
STATUS_SUCCESS
;
import
android.app.PendingIntent
;
import
android.content.BroadcastReceiver
;
import
android.content.Context
;
import
android.content.Intent
;
import
android.content.IntentFilter
;
import
android.content.pm.PackageInstaller.Session
;
import
android.content.pm.PackageInstaller.SessionParams
;
import
android.net.Uri
;
import
android.os.Build
;
import
com.topjohnwu.magisk.FileProvider
;
import
android.util.Log
;
import
java.io.File
;
import
java.io.FileInputStream
;
import
java.io.IOException
;
import
java.io.InputStream
;
import
java.io.OutputStream
;
import
java.util.concurrent.CountDownLatch
;
import
java.util.concurrent.TimeUnit
;
import
io.michaelrocks.paranoid.Obfuscate
;
@Obfuscate
public
class
APKInstall
{
public
static
Intent
installIntent
(
Context
c
,
File
apk
)
{
Intent
intent
=
new
Intent
(
Intent
.
ACTION_INSTALL_PACKAGE
);
intent
.
addFlags
(
Intent
.
FLAG_GRANT_READ_URI_PERMISSION
);
intent
.
addFlags
(
Intent
.
FLAG_ACTIVITY_NEW_TASK
);
if
(
Build
.
VERSION
.
SDK_INT
>=
24
)
{
intent
.
setData
(
FileProvider
.
getUriForFile
(
c
,
c
.
getPackageName
()
+
".provider"
,
apk
));
}
else
{
//noinspection ResultOfMethodCallIgnored SetWorldReadable
apk
.
setReadable
(
true
,
false
);
intent
.
setData
(
Uri
.
fromFile
(
apk
));
public
final
class
APKInstall
{
// @WorkerThread
public
static
void
installapk
(
Context
context
,
File
apk
)
{
//noinspection InlinedApi
var
flag
=
PendingIntent
.
FLAG_UPDATE_CURRENT
|
PendingIntent
.
FLAG_MUTABLE
;
var
action
=
APKInstall
.
class
.
getName
();
var
intent
=
new
Intent
(
action
).
setPackage
(
context
.
getPackageName
());
var
pending
=
PendingIntent
.
getBroadcast
(
context
,
0
,
intent
,
flag
);
var
installer
=
context
.
getPackageManager
().
getPackageInstaller
();
var
params
=
new
SessionParams
(
SessionParams
.
MODE_FULL_INSTALL
);
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
S
)
{
params
.
setRequireUserAction
(
SessionParams
.
USER_ACTION_NOT_REQUIRED
);
}
try
(
Session
session
=
installer
.
openSession
(
installer
.
createSession
(
params
)))
{
OutputStream
out
=
session
.
openWrite
(
apk
.
getName
(),
0
,
apk
.
length
());
try
(
var
in
=
new
FileInputStream
(
apk
);
out
)
{
transfer
(
in
,
out
);
}
session
.
commit
(
pending
.
getIntentSender
());
}
catch
(
IOException
e
)
{
Log
.
e
(
APKInstall
.
class
.
getSimpleName
(),
""
,
e
);
}
return
intent
;
}
public
static
void
install
(
Context
c
,
File
apk
)
{
c
.
startActivity
(
installIntent
(
c
,
apk
));
public
static
void
transfer
(
InputStream
in
,
OutputStream
out
)
throws
IOException
{
int
size
=
8192
;
var
buffer
=
new
byte
[
size
];
int
read
;
while
((
read
=
in
.
read
(
buffer
,
0
,
size
))
>=
0
)
{
out
.
write
(
buffer
,
0
,
read
);
}
}
public
static
void
registerInstallReceiver
(
Context
c
,
BroadcastReceiver
r
)
{
IntentFilter
filter
=
new
IntentFilter
();
filter
.
addAction
(
Intent
.
ACTION_PACKAGE_REPLACED
);
filter
.
addAction
(
Intent
.
ACTION_PACKAGE_ADDED
);
public
static
InstallReceiver
register
(
Context
context
,
String
packageName
,
Runnable
onSuccess
)
{
var
receiver
=
new
InstallReceiver
(
context
,
packageName
,
onSuccess
);
var
filter
=
new
IntentFilter
(
Intent
.
ACTION_PACKAGE_ADDED
);
filter
.
addDataScheme
(
"package"
);
c
.
getApplicationContext
().
registerReceiver
(
r
,
filter
);
context
.
registerReceiver
(
receiver
,
filter
);
context
.
registerReceiver
(
receiver
,
new
IntentFilter
(
APKInstall
.
class
.
getName
()));
return
receiver
;
}
public
static
class
InstallReceiver
extends
BroadcastReceiver
{
private
final
Context
context
;
private
final
String
packageName
;
private
final
Runnable
onSuccess
;
private
final
CountDownLatch
latch
=
new
CountDownLatch
(
1
);
private
Intent
intent
=
null
;
private
InstallReceiver
(
Context
context
,
String
packageName
,
Runnable
onSuccess
)
{
this
.
context
=
context
;
this
.
packageName
=
packageName
;
this
.
onSuccess
=
onSuccess
;
}
public
static
void
installHideResult
(
Activity
c
,
File
apk
)
{
Intent
intent
=
installIntent
(
c
,
apk
);
intent
.
putExtra
(
Intent
.
EXTRA_RETURN_RESULT
,
true
);
c
.
startActivityForResult
(
intent
,
0
);
// Ignore result, use install receiver
@Override
public
void
onReceive
(
Context
c
,
Intent
i
)
{
if
(
Intent
.
ACTION_PACKAGE_ADDED
.
equals
(
i
.
getAction
()))
{
Uri
data
=
i
.
getData
();
if
(
data
==
null
||
onSuccess
==
null
)
return
;
String
pkg
=
data
.
getSchemeSpecificPart
();
if
(
pkg
.
equals
(
packageName
))
{
onSuccess
.
run
();
context
.
unregisterReceiver
(
this
);
}
return
;
}
int
status
=
i
.
getIntExtra
(
EXTRA_STATUS
,
STATUS_FAILURE_INVALID
);
switch
(
status
)
{
case
STATUS_PENDING_USER_ACTION:
intent
=
i
.
getParcelableExtra
(
Intent
.
EXTRA_INTENT
);
break
;
case
STATUS_SUCCESS:
if
(
onSuccess
!=
null
)
onSuccess
.
run
();
default
:
context
.
unregisterReceiver
(
this
);
}
latch
.
countDown
();
}
// @WorkerThread @Nullable
public
Intent
waitIntent
()
{
try
{
//noinspection ResultOfMethodCallIgnored
latch
.
await
(
5
,
TimeUnit
.
SECONDS
);
}
catch
(
Exception
ignored
)
{
}
return
intent
;
}
}
}
app/src/main/java/com/topjohnwu/magisk/core/Provider.kt
View file @
baa19f0c
package
com.topjohnwu.magisk.core
import
android.content.ContentProvider
import
android.content.ContentValues
import
android.content.Context
import
android.content.pm.ProviderInfo
import
android.database.Cursor
import
android.net.Uri
import
android.os.Bundle
import
android.os.ParcelFileDescriptor
import
android.os.ParcelFileDescriptor.MODE_READ_ONLY
import
com.topjohnwu.magisk.FileProvider
import
com.topjohnwu.magisk.core.su.SuCallbackHandler
import
java.io.File
open
class
Provider
:
File
Provider
()
{
class
Provider
:
Content
Provider
()
{
override
fun
attachInfo
(
context
:
Context
,
info
:
ProviderInfo
?
)
{
override
fun
attachInfo
(
context
:
Context
,
info
:
ProviderInfo
)
{
super
.
attachInfo
(
context
.
wrap
(),
info
)
}
...
...
@@ -36,4 +38,11 @@ open class Provider : FileProvider() {
fun
PREFS_URI
(
pkg
:
String
)
=
Uri
.
Builder
().
scheme
(
"content"
).
authority
(
"$pkg.provider"
).
path
(
"prefs_file"
).
build
()
}
override
fun
onCreate
()
=
true
override
fun
getType
(
uri
:
Uri
):
String
?
=
null
override
fun
insert
(
uri
:
Uri
,
values
:
ContentValues
?):
Uri
?
=
null
override
fun
delete
(
uri
:
Uri
,
selection
:
String
?,
selectionArgs
:
Array
<
out
String
>?)
=
0
override
fun
update
(
uri
:
Uri
,
values
:
ContentValues
?,
selection
:
String
?,
selectionArgs
:
Array
<
out
String
>?)
=
0
override
fun
query
(
uri
:
Uri
,
projection
:
Array
<
out
String
>?,
selection
:
String
?,
selectionArgs
:
Array
<
out
String
>?,
sortOrder
:
String
?):
Cursor
?
=
null
}
app/src/main/java/com/topjohnwu/magisk/core/download/Subject.kt
View file @
baa19f0c
...
...
@@ -73,8 +73,12 @@ sealed class Subject : Parcelable {
val
externalFile
get
()
=
MediaStoreUtils
.
getFile
(
"$title.apk"
).
uri
override
fun
pendingIntent
(
context
:
Context
)
=
APKInstall
.
installIntent
(
context
,
file
.
toFile
()).
toPending
(
context
)
override
fun
pendingIntent
(
context
:
Context
):
PendingIntent
{
val
receiver
=
APKInstall
.
register
(
context
,
null
,
null
)
APKInstall
.
installapk
(
context
,
file
.
toFile
())
val
intent
=
receiver
.
waitIntent
()
?:
Intent
()
return
intent
.
toPending
(
context
)
}
}
@SuppressLint
(
"InlinedApi"
)
...
...
app/src/main/java/com/topjohnwu/magisk/core/tasks/HideAPK.kt
View file @
baa19f0c
package
com.topjohnwu.magisk.core.tasks
import
android.app.Activity
import
android.content.BroadcastReceiver
import
android.content.Context
import
android.content.Intent
import
android.widget.Toast
...
...
@@ -27,7 +26,6 @@ import timber.log.Timber
import
java.io.File
import
java.io.FileOutputStream
import
java.io.IOException
import
java.lang.ref.WeakReference
import
java.security.SecureRandom
object
HideAPK
{
...
...
@@ -41,8 +39,6 @@ object HideAPK {
const
val
MAX_LABEL_LENGTH
=
32
private
val
svc
get
()
=
ServiceLocator
.
networkService
private
val
Context
.
APK_URI
get
()
=
Provider
.
APK_URI
(
packageName
)
private
val
Context
.
PREFS_URI
get
()
=
Provider
.
PREFS_URI
(
packageName
)
private
fun
genPackageName
():
String
{
val
random
=
SecureRandom
()
...
...
@@ -92,35 +88,16 @@ object HideAPK {
return
true
}
private
class
WaitPackageReceiver
(
private
val
pkg
:
String
,
activity
:
Activity
)
:
BroadcastReceiver
()
{
private
val
activity
=
WeakReference
(
activity
)
private
fun
launchApp
():
Unit
=
activity
.
get
()
?.
run
{
val
intent
=
packageManager
.
getLaunchIntentForPackage
(
pkg
)
?:
return
private
fun
launchApp
(
activity
:
Activity
,
pkg
:
String
)
{
val
intent
=
activity
.
packageManager
.
getLaunchIntentForPackage
(
pkg
)
?:
return
Config
.
suManager
=
if
(
pkg
==
APPLICATION_ID
)
""
else
pkg
grantUriPermission
(
pkg
,
APK_URI
,
Intent
.
FLAG_GRANT_READ_URI_PERMISSION
)
grantUriPermission
(
pkg
,
PREFS_URI
,
Intent
.
FLAG_GRANT_READ_URI_PERMISSION
)
intent
.
putExtra
(
Const
.
Key
.
PREV_PKG
,
packageName
)
startActivity
(
intent
)
finish
()
}
?:
Unit
override
fun
onReceive
(
context
:
Context
,
intent
:
Intent
)
{
when
(
intent
.
action
?:
return
)
{
Intent
.
ACTION_PACKAGE_REPLACED
,
Intent
.
ACTION_PACKAGE_ADDED
->
{
val
newPkg
=
intent
.
data
?.
encodedSchemeSpecificPart
.
orEmpty
()
if
(
newPkg
==
pkg
)
{
context
.
unregisterReceiver
(
this
)
launchApp
()
}
}
}
}
val
self
=
activity
.
packageName
val
flag
=
Intent
.
FLAG_GRANT_READ_URI_PERMISSION
activity
.
grantUriPermission
(
pkg
,
Provider
.
APK_URI
(
self
),
flag
)
activity
.
grantUriPermission
(
pkg
,
Provider
.
PREFS_URI
(
self
),
flag
)
intent
.
putExtra
(
Const
.
Key
.
PREV_PKG
,
self
)
activity
.
startActivity
(
intent
)
activity
.
finish
()
}
private
suspend
fun
patchAndHide
(
activity
:
Activity
,
label
:
String
):
Boolean
{
...
...
@@ -141,9 +118,14 @@ object HideAPK {
return
false
// Install and auto launch app
APKInstall
.
registerInstallReceiver
(
activity
,
WaitPackageReceiver
(
pkg
,
activity
))
if
(!
Shell
.
su
(
"adb_pm_install $repack"
).
exec
().
isSuccess
)
APKInstall
.
installHideResult
(
activity
,
repack
)
val
receiver
=
APKInstall
.
register
(
activity
,
pkg
)
{
launchApp
(
activity
,
pkg
)
}
val
cmd
=
"adb_pm_install $repack ${activity.applicationInfo.uid}"
if
(!
Shell
.
su
(
cmd
).
exec
().
isSuccess
)
{
APKInstall
.
installapk
(
activity
,
repack
)
receiver
.
waitIntent
()
?.
let
{
activity
.
startActivity
(
it
)
}
}
return
true
}
...
...
@@ -157,8 +139,8 @@ object HideAPK {
val
result
=
withContext
(
Dispatchers
.
IO
)
{
patchAndHide
(
activity
,
label
)
}
dialog
.
dismiss
()
if
(!
result
)
{
dialog
.
dismiss
()
Utils
.
toast
(
R
.
string
.
failure
,
Toast
.
LENGTH_LONG
)
}
}
...
...
@@ -171,11 +153,15 @@ object HideAPK {
show
()
}
val
apk
=
DynAPK
.
current
(
activity
)
APKInstall
.
registerInstallReceiver
(
activity
,
WaitPackageReceiver
(
APPLICATION_ID
,
activity
))
Shell
.
su
(
"adb_pm_install $apk"
).
submit
{
val
receiver
=
APKInstall
.
register
(
activity
,
APPLICATION_ID
)
{
launchApp
(
activity
,
APPLICATION_ID
)
dialog
.
dismiss
()
if
(!
it
.
isSuccess
)
APKInstall
.
installHideResult
(
activity
,
apk
)
}
val
cmd
=
"adb_pm_install $apk ${activity.applicationInfo.uid}"
Shell
.
su
(
cmd
).
submit
(
Shell
.
EXECUTOR
)
{
ret
->
if
(
ret
.
isSuccess
)
return
@submit
APKInstall
.
installapk
(
activity
,
apk
)
receiver
.
waitIntent
()
?.
let
{
activity
.
startActivity
(
it
)
}
}
}
}
app/src/main/res/raw/manager.sh
View file @
baa19f0c
...
...
@@ -129,9 +129,11 @@ adb_pm_install() {
local
tmp
=
/data/local/tmp/temp.apk
cp
-f
"
$1
"
$tmp
chmod
644
$tmp
su 2000
-c
pm
install
$tmp
||
pm
install
$tmp
su 2000
-c
pm
install
$tmp
||
pm
install
$tmp
||
su 1000
-c
pm
install
$tmp
local
res
=
$?
rm
-f
$tmp
# Note: change this will kill self
[
$res
!=
0
]
&&
appops
set
"
$2
"
REQUEST_INSTALL_PACKAGES allow
return
$res
}
...
...
buildSrc/src/main/java/Codegen.kt
View file @
baa19f0c
...
...
@@ -105,7 +105,7 @@ fun genStubManifest(srcDir: File, outDir: File): String {
cmpList
.
add
(
Component
(
"com.topjohnwu.magisk.core.Provider"
,
"
File
Provider"
,
"
dummy.Dummy
Provider"
,
"""
|<provider
| android:name="%s"
...
...
stub/proguard-rules.pro
View file @
baa19f0c
...
...
@@ -29,5 +29,4 @@
-
allowaccessmodification
-
keepclassmembers
class
com
.
topjohnwu
.
magisk
.
dummy
.
*
{
<
init
>
();
}
-
keepclassmembers
class
com
.
topjohnwu
.
magisk
.
DownloadActivity
{
<
init
>
();
}
-
keepclassmembers
class
com
.
topjohnwu
.
magisk
.
FileProvider
{
<
init
>
();
}
-
keepclassmembers
class
com
.
topjohnwu
.
magisk
.
DelegateRootService
{
<
init
>
();
}
stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java
View file @
baa19f0c
...
...
@@ -12,6 +12,7 @@ import android.app.Activity;
import
android.app.AlertDialog
;
import
android.app.ProgressDialog
;
import
android.content.Context
;
import
android.content.Intent
;
import
android.os.AsyncTask
;
import
android.os.Bundle
;
import
android.util.Log
;
...
...
@@ -79,6 +80,7 @@ public class DownloadActivity extends Activity {
private
void
error
(
Throwable
e
)
{
Log
.
e
(
getClass
().
getSimpleName
(),
""
,
e
);
Toast
.
makeText
(
themed
,
e
.
getMessage
(),
Toast
.
LENGTH_LONG
).
show
();
finish
();
}
...
...
@@ -111,22 +113,22 @@ public class DownloadActivity extends Activity {
private
void
dlAPK
()
{
dialog
=
ProgressDialog
.
show
(
themed
,
getString
(
dling
),
getString
(
dling
)
+
" "
+
APP_NAME
,
true
);
Runnable
onSuccess
=
()
->
{
dialog
.
dismiss
();
Toast
.
makeText
(
themed
,
relaunch_app
,
Toast
.
LENGTH_LONG
).
show
();
finish
();
};
// Download and upgrade the app
File
apk
=
dynLoad
?
DynAPK
.
current
(
this
)
:
new
File
(
getCacheDir
(),
"manager.apk"
);
request
(
apkLink
).
setExecutor
(
AsyncTask
.
THREAD_POOL_EXECUTOR
).
getAsFile
(
apk
,
file
->
{
if
(
dynLoad
)
{
DynLoad
.
setup
(
this
);
runOnUiThread
(()
->
{
dialog
.
dismiss
();
Toast
.
makeText
(
themed
,
relaunch_app
,
Toast
.
LENGTH_LONG
).
show
();
finish
();
});
onSuccess
.
run
();
}
else
{
runOnUiThread
(()
->
{
dialog
.
dismiss
();
APKInstall
.
install
(
this
,
file
);
finish
();
});
var
receiver
=
APKInstall
.
register
(
this
,
BuildConfig
.
APPLICATION_ID
,
onSuccess
);
APKInstall
.
installapk
(
this
,
file
);
Intent
intent
=
receiver
.
waitIntent
();
if
(
intent
!=
null
)
startActivity
(
intent
);
}
});
}
...
...
@@ -141,15 +143,10 @@ public class DownloadActivity extends Activity {
InputStream
is
=
new
CipherInputStream
(
new
ByteArrayInputStream
(
Bytes
.
res
()),
cipher
);
try
(
InputStream
gzip
=
new
GZIPInputStream
(
is
);
OutputStream
out
=
new
FileOutputStream
(
apk
))
{
byte
[]
buf
=
new
byte
[
4096
];
for
(
int
read
;
(
read
=
gzip
.
read
(
buf
))
>=
0
;)
{
out
.
write
(
buf
,
0
,
read
);
}
APKInstall
.
transfer
(
gzip
,
out
);
}
DynAPK
.
addAssetPath
(
getResources
().
getAssets
(),
apk
.
getPath
());
}
catch
(
Exception
e
)
{
// Should not happen
e
.
printStackTrace
();
}
catch
(
Exception
ignored
)
{
}
}
...
...
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