Skip to content

Commit a028453

Browse files
committed
optimize.
1 parent 8cb63cb commit a028453

9 files changed

Lines changed: 102 additions & 103 deletions

File tree

‎app/build.gradle.kts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ android {
7373
minSdk = 26
7474
targetSdk = 36
7575
versionCode = calculateVersionCode()
76-
versionName = "4.2.7"
76+
versionName = "4.2.8"
7777

7878
vectorDrawables {
7979
useSupportLibrary = true

‎app/src/main/java/com/close/hook/ads/hook/system/PackageVisibilityHandler.kt‎

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,9 @@ object PackageVisibilityHandler {
2828

2929
private val threadWakeLock = Object()
3030

31+
@Volatile
32+
private var cachedSystemContext: Context? = null
33+
3134
fun init(xposed: XposedInterface) {
3235
xposed.log(Log.INFO, TAG, "Initializing Package Visibility Handler...")
3336

@@ -60,22 +63,27 @@ object PackageVisibilityHandler {
6063
try {
6164
val filter = IntentFilter(ACTION_UPDATE)
6265
if (Build.VERSION.SDK_INT >= 33) {
63-
sysContext.javaClass.getMethod("registerReceiver",
64-
BroadcastReceiver::class.java, IntentFilter::class.java, Int::class.javaPrimitiveType)
65-
.invoke(sysContext, updateReceiver, filter, 2)
66+
sysContext.javaClass.getMethod(
67+
"registerReceiver",
68+
BroadcastReceiver::class.java,
69+
IntentFilter::class.java,
70+
Int::class.javaPrimitiveType
71+
).invoke(sysContext, updateReceiver, filter, 2)
6672
} else {
6773
sysContext.registerReceiver(updateReceiver, filter)
6874
}
6975
isReceiverRegistered = true
7076
xposed.log(Log.INFO, TAG, "BroadcastReceiver registered successfully. System is ready.")
71-
} catch (ignored: Throwable) {}
77+
} catch (e: Throwable) {
78+
xposed.log(Log.WARN, TAG, "Failed to register BroadcastReceiver: ${e.message}")
79+
}
7280
}
7381
}
7482

7583
if (appsFilterInstance == null) {
7684
val binder = getService("package")
7785
val pms = if (binder != null) extractPMS(binder) else null
78-
86+
7987
if (pms != null) {
8088
val appsFilter = getFieldValue(pms, "mAppsFilter")
8189
if (appsFilter != null) {
@@ -90,7 +98,7 @@ object PackageVisibilityHandler {
9098
appsFilterInstance = appsFilter
9199
cacheEnabledField = findField(appsFilter.javaClass, "mCacheEnabled")
92100
disabledPackagesInstance = getFieldValue(featureConfig, "mDisabledPackages")
93-
101+
94102
if (disabledPackagesInstance != null) {
95103
val arraySetClass = Class.forName("android.util.ArraySet")
96104
addMethod = arraySetClass.getMethod("add", Object::class.java)
@@ -148,12 +156,16 @@ object PackageVisibilityHandler {
148156

149157
if (isReceiverRegistered) {
150158
synchronized(threadWakeLock) {
151-
threadWakeLock.wait(60000L)
159+
threadWakeLock.wait(60000L)
152160
}
153161
} else {
154162
Thread.sleep(5000)
155163
}
156164

165+
} catch (e: InterruptedException) {
166+
xposed.log(Log.INFO, TAG, "Daemon thread interrupted, exiting.")
167+
Thread.currentThread().interrupt()
168+
break
157169
} catch (e: Throwable) {
158170
xposed.log(Log.ERROR, TAG, "Daemon error: ${Log.getStackTraceString(e)}")
159171
if (e is ReflectiveOperationException) appsFilterInstance = null
@@ -193,11 +205,16 @@ object PackageVisibilityHandler {
193205
}
194206

195207
private fun getSystemContext(): Context? {
208+
cachedSystemContext?.let { return it }
196209
return try {
197210
val atClass = Class.forName("android.app.ActivityThread")
198211
val at = atClass.getMethod("currentActivityThread").invoke(null)
199-
atClass.getMethod("getSystemContext").invoke(at) as Context
200-
} catch (e: Exception) { null }
212+
val ctx = atClass.getMethod("getSystemContext").invoke(at) as? Context
213+
cachedSystemContext = ctx
214+
ctx
215+
} catch (e: Exception) {
216+
null
217+
}
201218
}
202219

203220
private fun getService(name: String): IBinder? {

‎app/src/main/java/com/close/hook/ads/preference/HookPrefs.kt‎

Lines changed: 68 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -41,9 +41,18 @@ object HookPrefs {
4141
const val KEY_ENABLE_PACKAGE_VISIBILITY_BYPASS = "enable_package_visibility_bypass"
4242
const val KEY_REQUEST_CACHE_EXPIRATION = "request_cache_expiration"
4343

44-
private val jsonFormat = Json {
45-
ignoreUnknownKeys = true
46-
prettyPrint = true
44+
private val VISIBILITY_RELEVANT_KEY_PREFIXES = arrayOf(
45+
"switch_one_", "switch_two_", "switch_three_", "switch_four_",
46+
"switch_five_", "switch_six_", "switch_seven_", "switch_eight_",
47+
"switch_nine_", "overall_hook_enabled_"
48+
)
49+
private val VISIBILITY_RELEVANT_EXACT_KEYS = setOf(
50+
KEY_ENABLE_PACKAGE_VISIBILITY_BYPASS
51+
)
52+
53+
private val jsonFormat = Json {
54+
ignoreUnknownKeys = true
55+
prettyPrint = true
4756
isLenient = true
4857
}
4958

@@ -78,7 +87,7 @@ object HookPrefs {
7887

7988
private val generalSettingsCache = MutableStateFlow<JsonObject?>(null)
8089
val generalSettingsFlow = generalSettingsCache.asStateFlow()
81-
90+
8291
private val cacheLock = Any()
8392

8493
private fun getSettingsJson(): JsonObject {
@@ -90,31 +99,35 @@ object HookPrefs {
9099
if (cachedAgain != null) return cachedAgain
91100

92101
val jsonObject = readSettingsFromFile()
93-
if (jsonObject != null) {
94-
generalSettingsCache.value = jsonObject
95-
return jsonObject
96-
} else {
97-
return JsonObject(emptyMap())
98-
}
102+
generalSettingsCache.value = jsonObject ?: JsonObject(emptyMap())
103+
return generalSettingsCache.value!!
99104
}
100105
}
101106

102-
private fun updateSetting(transform: (MutableMap<String, JsonElement>) -> Unit) {
107+
private fun updateSetting(
108+
affectedKeys: Set<String> = emptySet(),
109+
transform: (MutableMap<String, JsonElement>) -> Unit
110+
) {
103111
synchronized(cacheLock) {
104-
val baseline = generalSettingsCache.value ?: readSettingsFromFile() ?: JsonObject(emptyMap())
105-
112+
val baseline = generalSettingsCache.value
113+
?: readSettingsFromFile()
114+
?: JsonObject(emptyMap())
106115
val mutableMap = baseline.toMutableMap()
107116
transform(mutableMap)
108-
val newJson = JsonObject(mutableMap)
109-
generalSettingsCache.value = newJson
117+
generalSettingsCache.value = JsonObject(mutableMap)
118+
}
119+
120+
val shouldNotify = affectedKeys.any { key ->
121+
key == KEY_ENABLE_PACKAGE_VISIBILITY_BYPASS ||
122+
VISIBILITY_RELEVANT_KEY_PREFIXES.any { key.startsWith(it) }
110123
}
111124

112125
ioScope.launch {
113126
try {
114-
val currentLatestJson = generalSettingsCache.value ?: return@launch
115-
val jsonString = jsonFormat.encodeToString(currentLatestJson)
127+
val latestJson = generalSettingsCache.value ?: return@launch
128+
val jsonString = jsonFormat.encodeToString(latestJson)
116129

117-
if (writeTextToFile(FILE_GENERAL_SETTINGS, jsonString)) {
130+
if (writeTextToFile(FILE_GENERAL_SETTINGS, jsonString) && shouldNotify) {
118131
closeApp.sendBroadcast(
119132
Intent("com.close.hook.ads.ACTION_UPDATE_PKG_VISIBILITY").apply {
120133
setPackage("android")
@@ -129,48 +142,40 @@ object HookPrefs {
129142

130143
fun getBoolean(key: String, defaultValue: Boolean): Boolean {
131144
val element = getSettingsJson()[key]
132-
return if (element is JsonPrimitive) {
133-
element.booleanOrNull ?: defaultValue
134-
} else {
135-
defaultValue
136-
}
145+
return if (element is JsonPrimitive) element.booleanOrNull ?: defaultValue
146+
else defaultValue
137147
}
138148

139149
fun setBoolean(key: String, value: Boolean) {
140-
updateSetting { it[key] = JsonPrimitive(value) }
150+
updateSetting(affectedKeys = setOf(key)) { it[key] = JsonPrimitive(value) }
141151
}
142-
152+
143153
fun getLong(key: String, defaultValue: Long): Long {
144154
val element = getSettingsJson()[key]
145155
return if (element is JsonPrimitive) {
146156
element.longOrNull ?: element.contentOrNull?.toLongOrNull() ?: defaultValue
147-
} else {
148-
defaultValue
149-
}
157+
} else defaultValue
150158
}
151159

152160
fun setLong(key: String, value: Long) {
153-
updateSetting { it[key] = JsonPrimitive(value) }
161+
updateSetting(affectedKeys = setOf(key)) { it[key] = JsonPrimitive(value) }
154162
}
155163

156164
fun getString(key: String, defaultValue: String?): String? {
157165
val element = getSettingsJson()[key]
158-
return if (element is JsonPrimitive) {
159-
element.contentOrNull ?: defaultValue
160-
} else {
161-
defaultValue
162-
}
166+
return if (element is JsonPrimitive) element.contentOrNull ?: defaultValue
167+
else defaultValue
163168
}
164169

165170
fun setString(key: String, value: String?) {
166-
updateSetting {
171+
updateSetting(affectedKeys = setOf(key)) {
167172
if (value == null) it.remove(key) else it[key] = JsonPrimitive(value)
168173
}
169174
}
170175

171176
fun setMultiple(updates: Map<String, Any>) {
172177
if (updates.isEmpty()) return
173-
updateSetting { map ->
178+
updateSetting(affectedKeys = updates.keys) { map ->
174179
updates.forEach { (k, v) ->
175180
val jsonElement = when (v) {
176181
is Boolean -> JsonPrimitive(v)
@@ -184,29 +189,25 @@ object HookPrefs {
184189
}
185190

186191
fun remove(key: String) {
187-
updateSetting { it.remove(key) }
192+
updateSetting(affectedKeys = setOf(key)) { it.remove(key) }
188193
}
189194

190195
fun clear() {
191196
updateSetting { it.clear() }
192197
}
193198

194-
fun contains(key: String): Boolean {
195-
return getSettingsJson().containsKey(key)
196-
}
199+
fun contains(key: String): Boolean = getSettingsJson().containsKey(key)
197200

198201
fun getAll(): Map<String, Any?> {
199202
val json = getSettingsJson()
200203
return json.mapValues { entry ->
201204
val primitive = entry.value as? JsonPrimitive
202205
when {
203206
primitive?.isString == true -> primitive.content
204-
primitive != null -> {
205-
primitive.booleanOrNull
206-
?: primitive.longOrNull
207-
?: primitive.doubleOrNull
208-
?: primitive.content
209-
}
207+
primitive != null -> primitive.booleanOrNull
208+
?: primitive.longOrNull
209+
?: primitive.doubleOrNull
210+
?: primitive.content
210211
else -> entry.value.toString()
211212
}
212213
}
@@ -216,11 +217,11 @@ object HookPrefs {
216217

217218
fun getCustomHookConfigs(packageName: String?): List<CustomHookInfo> {
218219
val effectiveKey = packageName ?: GLOBAL_KEY
219-
220+
220221
customHookCache[effectiveKey]?.let { return it }
221222

222223
val content = readAllTextFromFile(buildFileName(FILE_PREFIX_CUSTOM_HOOK, effectiveKey))
223-
224+
224225
if (content == null) {
225226
Log.w(TAG, "Service unavailable. Returning empty custom hooks without caching.")
226227
return emptyList()
@@ -236,14 +237,14 @@ object HookPrefs {
236237
emptyList()
237238
}
238239
}
239-
240+
240241
customHookCache[effectiveKey] = result
241242
return result
242243
}
243244

244245
fun setCustomHookConfigs(packageName: String?, configs: List<CustomHookInfo>) {
245246
val effectiveKey = packageName ?: GLOBAL_KEY
246-
247+
247248
if (configs.isEmpty()) {
248249
customHookCache.remove(effectiveKey)
249250
} else {
@@ -277,9 +278,7 @@ object HookPrefs {
277278

278279
private fun readSettingsFromFile(): JsonObject? {
279280
val content = readAllTextFromFile(FILE_GENERAL_SETTINGS) ?: return null
280-
281281
if (content.isBlank()) return JsonObject(emptyMap())
282-
283282
return try {
284283
jsonFormat.parseToJsonElement(content) as? JsonObject ?: JsonObject(emptyMap())
285284
} catch (e: Exception) {
@@ -294,22 +293,21 @@ object HookPrefs {
294293
Log.w(TAG, "fileAccessor is null. Framework IPC disconnected.")
295294
return null
296295
}
297-
296+
298297
try {
299298
val files = accessor.listRemoteFiles()
300-
if (files == null || !files.contains(fileName)) {
301-
return ""
302-
}
299+
if (files == null || !files.contains(fileName)) return ""
303300
} catch (e: Exception) {
304301
Log.e(TAG, "Error checking remote files (IPC failure)", e)
305302
return null
306303
}
307304

308305
return try {
309306
accessor.openRemoteFile(fileName, "r")?.use { pfd ->
310-
InputStreamReader(ParcelFileDescriptor.AutoCloseInputStream(pfd), StandardCharsets.UTF_8).use {
311-
it.readText()
312-
}
307+
InputStreamReader(
308+
ParcelFileDescriptor.AutoCloseInputStream(pfd),
309+
StandardCharsets.UTF_8
310+
).use { it.readText() }
313311
} ?: ""
314312
} catch (e: Exception) {
315313
Log.e(TAG, "Error reading remote file", e)
@@ -323,9 +321,9 @@ object HookPrefs {
323321
accessor.openRemoteFile(fileName, "rw")?.use { pfd ->
324322
ParcelFileDescriptor.AutoCloseOutputStream(pfd).use { fos ->
325323
fos.channel.truncate(0)
326-
fos.bufferedWriter(StandardCharsets.UTF_8).use { writer ->
327-
writer.write(content)
328-
}
324+
val writer = fos.bufferedWriter(StandardCharsets.UTF_8)
325+
writer.write(content)
326+
writer.flush()
329327
}
330328
}
331329
true
@@ -344,31 +342,24 @@ object HookPrefs {
344342
}
345343
}
346344

347-
internal fun buildKey(prefix: String, packageName: String?): String {
348-
return prefix + (packageName ?: GLOBAL_KEY)
349-
}
345+
internal fun buildKey(prefix: String, packageName: String?): String =
346+
prefix + (packageName ?: GLOBAL_KEY)
350347

351-
private fun buildFileName(prefix: String, key: String): String {
352-
return "$prefix$key.json"
353-
}
348+
private fun buildFileName(prefix: String, key: String): String = "$prefix$key.json"
354349

355-
fun getOverallHookEnabled(packageName: String?): Boolean {
356-
return getBoolean(buildKey(KEY_PREFIX_OVERALL_HOOK, packageName), false)
357-
}
350+
fun getOverallHookEnabled(packageName: String?): Boolean =
351+
getBoolean(buildKey(KEY_PREFIX_OVERALL_HOOK, packageName), false)
358352

359353
fun setOverallHookEnabled(packageName: String?, isEnabled: Boolean) {
360354
setBoolean(buildKey(KEY_PREFIX_OVERALL_HOOK, packageName), isEnabled)
361355
}
362356

363-
fun getEnableLogging(packageName: String?): Boolean {
364-
return getBoolean(buildKey(KEY_PREFIX_ENABLE_LOGGING, packageName), false)
365-
}
357+
fun getEnableLogging(packageName: String?): Boolean =
358+
getBoolean(buildKey(KEY_PREFIX_ENABLE_LOGGING, packageName), false)
366359

367360
fun setEnableLogging(packageName: String?, isEnabled: Boolean) {
368361
setBoolean(buildKey(KEY_PREFIX_ENABLE_LOGGING, packageName), isEnabled)
369362
}
370363

371-
fun getRequestCacheExpiration(): Long {
372-
return getString(KEY_REQUEST_CACHE_EXPIRATION, "5")?.toLongOrNull() ?: 5L
373-
}
364+
fun getRequestCacheExpiration(): Long = getLong(KEY_REQUEST_CACHE_EXPIRATION, 5L)
374365
}

0 commit comments

Comments
 (0)