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
668e5492
Commit
668e5492
authored
Feb 14, 2022
by
topjohnwu
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Refactor APKInstall
parent
256ff31d
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
122 additions
and
98 deletions
+122
-98
APKInstall.java
.../src/main/java/com/topjohnwu/magisk/utils/APKInstall.java
+80
-70
DownloadService.kt
...ava/com/topjohnwu/magisk/core/download/DownloadService.kt
+8
-8
HideAPK.kt
app/src/main/java/com/topjohnwu/magisk/core/tasks/HideAPK.kt
+23
-16
Codegen.kt
buildSrc/src/main/java/Codegen.kt
+1
-0
DownloadActivity.java
.../src/main/java/com/topjohnwu/magisk/DownloadActivity.java
+10
-4
No files found.
app/shared/src/main/java/com/topjohnwu/magisk/utils/APKInstall.java
View file @
668e5492
...
...
@@ -10,11 +10,9 @@ 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
android.util.Log
;
import
java.io.File
;
import
java.io.FileInputStream
;
...
...
@@ -31,51 +29,6 @@ import io.michaelrocks.paranoid.Obfuscate;
@Obfuscate
public
final
class
APKInstall
{
private
static
final
String
ACTION_SESSION_UPDATE
=
"ACTION_SESSION_UPDATE"
;
// @WorkerThread
public
static
void
install
(
Context
context
,
File
apk
)
{
try
(
var
src
=
new
FileInputStream
(
apk
);
var
out
=
openStream
(
context
))
{
if
(
out
!=
null
)
transfer
(
src
,
out
);
}
catch
(
IOException
e
)
{
Log
.
e
(
APKInstall
.
class
.
getSimpleName
(),
""
,
e
);
}
}
public
static
OutputStream
openStream
(
Context
context
)
{
//noinspection InlinedApi
var
flag
=
PendingIntent
.
FLAG_UPDATE_CURRENT
|
PendingIntent
.
FLAG_MUTABLE
;
var
intent
=
new
Intent
(
ACTION_SESSION_UPDATE
).
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
));
var
out
=
session
.
openWrite
(
UUID
.
randomUUID
().
toString
(),
0
,
-
1
);
return
new
FilterOutputStream
(
out
)
{
@Override
public
void
write
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
out
.
write
(
b
,
off
,
len
);
}
@Override
public
void
close
()
throws
IOException
{
super
.
close
();
session
.
commit
(
pending
.
getIntentSender
());
session
.
close
();
}
};
}
catch
(
IOException
e
)
{
Log
.
e
(
APKInstall
.
class
.
getSimpleName
(),
""
,
e
);
}
return
null
;
}
public
static
void
transfer
(
InputStream
in
,
OutputStream
out
)
throws
IOException
{
int
size
=
8192
;
var
buffer
=
new
byte
[
size
];
...
...
@@ -85,21 +38,37 @@ public final class APKInstall {
}
}
public
static
InstallReceiver
register
(
Context
context
,
String
packageName
,
Runnable
onSuccess
)
{
var
receiver
=
new
InstallReceiver
(
packageName
,
onSuccess
);
var
filter
=
new
IntentFilter
(
Intent
.
ACTION_PACKAGE_ADDED
);
filter
.
addDataScheme
(
"package"
);
context
.
registerReceiver
(
receiver
,
filter
);
context
.
registerReceiver
(
receiver
,
new
IntentFilter
(
ACTION_SESSION_UPDATE
));
public
static
Session
startSession
(
Context
context
)
{
return
startSession
(
context
,
null
,
null
);
}
public
static
Session
startSession
(
Context
context
,
String
pkg
,
Runnable
onSuccess
)
{
var
receiver
=
new
InstallReceiver
(
pkg
,
onSuccess
);
context
=
context
.
getApplicationContext
();
if
(
pkg
!=
null
)
{
// If pkg is not null, look for package added event
var
filter
=
new
IntentFilter
(
Intent
.
ACTION_PACKAGE_ADDED
);
filter
.
addDataScheme
(
"package"
);
context
.
registerReceiver
(
receiver
,
filter
);
}
context
.
registerReceiver
(
receiver
,
new
IntentFilter
(
receiver
.
sessionId
));
return
receiver
;
}
public
static
class
InstallReceiver
extends
BroadcastReceiver
{
public
interface
Session
{
OutputStream
openStream
(
Context
context
)
throws
IOException
;
void
install
(
Context
context
,
File
apk
)
throws
IOException
;
Intent
waitIntent
();
}
private
static
class
InstallReceiver
extends
BroadcastReceiver
implements
Session
{
private
final
String
packageName
;
private
final
Runnable
onSuccess
;
private
final
CountDownLatch
latch
=
new
CountDownLatch
(
1
);
private
Intent
userAction
=
null
;
final
String
sessionId
=
UUID
.
randomUUID
().
toString
();
private
InstallReceiver
(
String
packageName
,
Runnable
onSuccess
)
{
this
.
packageName
=
packageName
;
this
.
onSuccess
=
onSuccess
;
...
...
@@ -113,27 +82,32 @@ public final class APKInstall {
return
;
String
pkg
=
data
.
getSchemeSpecificPart
();
if
(
pkg
.
equals
(
packageName
))
{
if
(
onSuccess
!=
null
)
onSuccess
.
run
();
context
.
unregisterReceiver
(
this
);
onSuccess
(
context
);
}
return
;
}
int
status
=
intent
.
getIntExtra
(
EXTRA_STATUS
,
STATUS_FAILURE_INVALID
);
switch
(
status
)
{
case
STATUS_PENDING_USER_ACTION:
userAction
=
intent
.
getParcelableExtra
(
Intent
.
EXTRA_INTENT
);
break
;
case
STATUS_SUCCESS:
if
(
onSuccess
!=
null
)
onSuccess
.
run
();
default
:
context
.
unregisterReceiver
(
this
);
}
else
if
(
sessionId
.
equals
(
intent
.
getAction
()))
{
int
status
=
intent
.
getIntExtra
(
EXTRA_STATUS
,
STATUS_FAILURE_INVALID
);
switch
(
status
)
{
case
STATUS_PENDING_USER_ACTION:
userAction
=
intent
.
getParcelableExtra
(
Intent
.
EXTRA_INTENT
);
break
;
case
STATUS_SUCCESS:
if
(
packageName
==
null
)
{
onSuccess
(
context
);
}
break
;
}
latch
.
countDown
();
}
latch
.
countDown
();
}
private
void
onSuccess
(
Context
context
)
{
if
(
onSuccess
!=
null
)
onSuccess
.
run
();
context
.
getApplicationContext
().
unregisterReceiver
(
this
);
}
// @WorkerThread @Nullable
@Override
public
Intent
waitIntent
()
{
try
{
//noinspection ResultOfMethodCallIgnored
...
...
@@ -141,5 +115,41 @@ public final class APKInstall {
}
catch
(
Exception
ignored
)
{}
return
userAction
;
}
@Override
public
OutputStream
openStream
(
Context
context
)
throws
IOException
{
// noinspection InlinedApi
var
flag
=
PendingIntent
.
FLAG_UPDATE_CURRENT
|
PendingIntent
.
FLAG_MUTABLE
;
var
intent
=
new
Intent
(
sessionId
).
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
);
}
var
session
=
installer
.
openSession
(
installer
.
createSession
(
params
));
var
out
=
session
.
openWrite
(
sessionId
,
0
,
-
1
);
return
new
FilterOutputStream
(
out
)
{
@Override
public
void
write
(
byte
[]
b
,
int
off
,
int
len
)
throws
IOException
{
out
.
write
(
b
,
off
,
len
);
}
@Override
public
void
close
()
throws
IOException
{
super
.
close
();
session
.
commit
(
pending
.
getIntentSender
());
session
.
close
();
}
};
}
@Override
public
void
install
(
Context
context
,
File
apk
)
throws
IOException
{
try
(
var
src
=
new
FileInputStream
(
apk
);
var
out
=
openStream
(
context
))
{
transfer
(
src
,
out
);
}
}
}
}
app/src/main/java/com/topjohnwu/magisk/core/download/DownloadService.kt
View file @
668e5492
...
...
@@ -72,9 +72,9 @@ class DownloadService : NotificationService() {
}
}
private
fun
openApkSessio
n
():
OutputStream
{
private
fun
APKInstall
.
Session
.
ope
n
():
OutputStream
{
Config
.
showUpdateDone
=
true
return
APKInstall
.
openStream
(
this
)
return
openStream
(
this
@DownloadService
)
}
private
suspend
fun
handleApp
(
stream
:
InputStream
,
subject
:
Subject
.
App
)
{
...
...
@@ -110,9 +110,9 @@ class DownloadService : NotificationService() {
apk
.
delete
()
// Install
val
receiver
=
APKInstall
.
register
(
this
,
null
,
null
)
patched
.
inputStream
().
copyAndClose
(
openApkSessio
n
())
subject
.
intent
=
receiver
.
waitIntent
()
val
session
=
APKInstall
.
startSession
(
this
)
patched
.
inputStream
().
copyAndClose
(
session
.
ope
n
())
subject
.
intent
=
session
.
waitIntent
()
patched
.
delete
()
}
else
{
...
...
@@ -131,9 +131,9 @@ class DownloadService : NotificationService() {
throw
e
}
}
else
{
val
receiver
=
APKInstall
.
register
(
this
,
null
,
null
)
writeTee
(
openApkSessio
n
())
subject
.
intent
=
receiver
.
waitIntent
()
val
session
=
APKInstall
.
startSession
(
this
)
writeTee
(
session
.
ope
n
())
subject
.
intent
=
session
.
waitIntent
()
}
}
...
...
app/src/main/java/com/topjohnwu/magisk/core/tasks/HideAPK.kt
View file @
668e5492
package
com.topjohnwu.magisk.core.tasks
import
android.app.Activity
import
android.app.ProgressDialog
import
android.content.Context
import
android.content.Intent
import
android.widget.Toast
...
...
@@ -20,8 +21,7 @@ import com.topjohnwu.magisk.signing.SignApk
import
com.topjohnwu.magisk.utils.APKInstall
import
com.topjohnwu.magisk.utils.Utils
import
com.topjohnwu.superuser.Shell
import
kotlinx.coroutines.Dispatchers
import
kotlinx.coroutines.withContext
import
kotlinx.coroutines.*
import
timber.log.Timber
import
java.io.File
import
java.io.FileOutputStream
...
...
@@ -108,7 +108,8 @@ object HideAPK {
Timber
.
e
(
e
)
stub
.
createNewFile
()
val
cmd
=
"\$MAGISKBIN/magiskinit -x manager ${stub.path}"
if
(!
Shell
.
su
(
cmd
).
exec
().
isSuccess
)
return
false
if
(!
Shell
.
su
(
cmd
).
exec
().
isSuccess
)
return
false
}
// Generate a new random package name and signature
...
...
@@ -120,20 +121,22 @@ object HideAPK {
return
false
// Install and auto launch app
val
receiver
=
APKInstall
.
register
(
activity
,
pkg
)
{
val
session
=
APKInstall
.
startSession
(
activity
,
pkg
)
{
launchApp
(
activity
,
pkg
)
}
val
cmd
=
"adb_pm_install $repack ${activity.applicationInfo.uid}"
if
(!
Shell
.
su
(
cmd
).
exec
().
isSuccess
)
{
APKInstall
.
install
(
activity
,
repack
)
receiver
.
waitIntent
()
?.
let
{
activity
.
startActivity
(
it
)
}
try
{
session
.
install
(
activity
,
repack
)
}
catch
(
e
:
IOException
)
{
Timber
.
e
(
e
)
return
false
}
session
.
waitIntent
()
?.
let
{
activity
.
startActivity
(
it
)
}
return
true
}
@Suppress
(
"DEPRECATION"
)
suspend
fun
hide
(
activity
:
Activity
,
label
:
String
)
{
val
dialog
=
android
.
app
.
ProgressDialog
(
activity
).
apply
{
val
dialog
=
ProgressDialog
(
activity
).
apply
{
setTitle
(
activity
.
getString
(
R
.
string
.
hide_app_title
))
isIndeterminate
=
true
setCancelable
(
false
)
...
...
@@ -148,24 +151,28 @@ object HideAPK {
}
}
@DelicateCoroutinesApi
@Suppress
(
"DEPRECATION"
)
fun
restore
(
activity
:
Activity
)
{
val
dialog
=
android
.
app
.
ProgressDialog
(
activity
).
apply
{
val
dialog
=
ProgressDialog
(
activity
).
apply
{
setTitle
(
activity
.
getString
(
R
.
string
.
restore_img_msg
))
isIndeterminate
=
true
setCancelable
(
false
)
show
()
}
val
apk
=
StubApk
.
current
(
activity
)
val
receiver
=
APKInstall
.
register
(
activity
,
APPLICATION_ID
)
{
val
session
=
APKInstall
.
startSession
(
activity
,
APPLICATION_ID
)
{
launchApp
(
activity
,
APPLICATION_ID
)
dialog
.
dismiss
()
}
val
cmd
=
"adb_pm_install $apk ${activity.applicationInfo.uid}"
Shell
.
su
(
cmd
).
submit
(
Shell
.
EXECUTOR
)
{
ret
->
if
(
ret
.
isSuccess
)
return
@submit
APKInstall
.
install
(
activity
,
apk
)
receiver
.
waitIntent
()
?.
let
{
activity
.
startActivity
(
it
)
}
GlobalScope
.
launch
(
Dispatchers
.
IO
)
{
try
{
session
.
install
(
activity
,
apk
)
}
catch
(
e
:
IOException
)
{
Timber
.
e
(
e
)
return
@launch
}
session
.
waitIntent
()
?.
let
{
activity
.
startActivity
(
it
)
}
}
}
}
buildSrc/src/main/java/Codegen.kt
View file @
668e5492
...
...
@@ -99,6 +99,7 @@ fun genStubManifest(srcDir: File, outDir: File): String {
| <intent-filter>
| <action android:name="android.intent.action.LOCALE_CHANGED" />
| <action android:name="android.intent.action.UID_REMOVED" />
| <action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
| </intent-filter>
| <intent-filter>
| <action android:name="android.intent.action.PACKAGE_REPLACED" />
...
...
stub/src/main/java/com/topjohnwu/magisk/DownloadActivity.java
View file @
668e5492
...
...
@@ -26,6 +26,7 @@ import org.json.JSONException;
import
java.io.ByteArrayInputStream
;
import
java.io.File
;
import
java.io.FileOutputStream
;
import
java.io.IOException
;
import
javax.crypto.Cipher
;
import
javax.crypto.CipherInputStream
;
...
...
@@ -126,10 +127,15 @@ public class DownloadActivity extends Activity {
if
(
dynLoad
)
{
runOnUiThread
(
onSuccess
);
}
else
{
var
receiver
=
APKInstall
.
register
(
this
,
BuildConfig
.
APPLICATION_ID
,
onSuccess
);
APKInstall
.
install
(
this
,
file
);
Intent
intent
=
receiver
.
waitIntent
();
if
(
intent
!=
null
)
startActivity
(
intent
);
var
session
=
APKInstall
.
startSession
(
this
);
try
{
session
.
install
(
this
,
file
);
Intent
intent
=
session
.
waitIntent
();
if
(
intent
!=
null
)
startActivity
(
intent
);
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
}
}
});
}
...
...
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