├── LICENSE ├── README.md ├── app ├── assets │ └── test.pdf ├── build.gradle ├── mk.sh └── src │ └── main │ ├── AndroidManifest.xml │ ├── aidl │ ├── android │ │ └── media │ │ │ ├── AttributionSourceState.aidl │ │ │ ├── AudioAttributesInternal.aidl │ │ │ ├── AudioClient.aidl │ │ │ ├── AudioConfigBase.aidl │ │ │ ├── AudioContentType.aidl │ │ │ ├── AudioFormat.aidl │ │ │ ├── AudioSourceType.aidl │ │ │ ├── AudioUsage.aidl │ │ │ ├── CreateRecordRequest.aidl │ │ │ ├── CreateRecordResponse.aidl │ │ │ └── SharedFileRegion.aidl │ └── com │ │ └── ifma │ │ └── cmpt │ │ └── demo │ │ ├── IBinderTest.aidl │ │ └── IBinderTestCallback.aidl │ ├── java │ └── com │ │ └── ifma │ │ └── cmpt │ │ └── demo │ │ ├── DemoApplication.java │ │ ├── DemoComponentFactory.java │ │ ├── FakeApplication.java │ │ ├── NativeCall.java │ │ ├── main │ │ ├── ConsoleActivity.java │ │ ├── MainActivity.java │ │ ├── MainProvider.java │ │ ├── MainReceiver.java │ │ └── MainService.java │ │ ├── module │ │ ├── ClassDumper.java │ │ ├── ClipboadData.java │ │ ├── Consts.java │ │ ├── LauncherMonitor.java │ │ └── PackageDumper.java │ │ ├── sub │ │ ├── DocumentReceiverActivity.java │ │ ├── SingleProvider.java │ │ ├── SubActivity.java │ │ ├── SubPermissionProvider.java │ │ ├── SubProvider.java │ │ ├── SubReceiver.java │ │ └── SubService.java │ │ └── test │ │ ├── FireyerAccessibilityCase.java │ │ ├── FireyerCaseConsts.java │ │ ├── FireyerDeviceModelCase.java │ │ ├── FireyerDevicePolicyManagerCase.java │ │ ├── FireyerPackageCase.java │ │ ├── FireyerRuntimeCase.java │ │ └── FireyerStackCase.java │ └── res │ ├── drawable-hdpi │ ├── activity.png │ └── ic_launcher.png │ ├── drawable │ ├── list_item_bg_single_selected.xml │ ├── list_item_bg_single_selector.xml │ ├── list_item_bg_single_unselected.xml │ └── welcome.png │ ├── layout │ ├── activity_console.xml │ ├── activity_main.xml │ ├── activity_sub.xml │ ├── activity_test.xml │ └── dialog_input.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── raw │ └── testraw.txt │ ├── values │ ├── booleans.xml │ ├── colors.xml │ ├── dimens.xml │ ├── integers.xml │ ├── strings.xml │ └── styles.xml │ └── xml │ └── test_provider.xml ├── build.gradle ├── cmpt-cocollider ├── build.gradle ├── mk.sh ├── pom.json └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── ifma │ │ └── cmpt │ │ └── cocollider │ │ └── CoColliderManager.java │ └── mk.sh ├── cmpt-fireyer ├── build.gradle ├── mk.sh ├── pom.json └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── ifma │ │ └── cmpt │ │ └── fireyer │ │ ├── FireyerManager.java │ │ ├── FireyerNative.java │ │ └── FireyerUtils.java │ ├── jni │ ├── Android.mk │ ├── Application.mk │ ├── CMakeLists.txt │ ├── inc │ │ ├── arch.h │ │ ├── assembly-arm.h │ │ ├── assembly-arm64.h │ │ ├── assembly.h │ │ └── fireyer_native.h │ └── src │ │ ├── fireyer_main.cpp │ │ └── fireyer_native.cpp │ └── mk.sh ├── cocollider.py ├── files ├── default.gradle └── fireyer.keystore ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── img ├── 1.png ├── fireyer.svg └── thanks.png ├── mk.py ├── proguard-rules.pro └── settings.gradle /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2024 iofomo 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

2 | 3 | Fireyer 4 | 5 |

6 | 7 |

8 | Android:9.x~14.x 9 |

10 | 11 | 12 | ## 说明 13 | 14 | `Fire` + `Eye` = `Fireyer`(火眼),`Fireyer`项目是我们在做虚拟化沙箱产品过程中的内部副产品。目的是为了校验我们的虚拟化环境构建是否存在漏洞。在内部作为我们产品的黑白检测工具应用,可以保障我们的每次更新的产品质量,提升开发效率。对于开发沙箱,虚拟化等相关场景产品的伙伴也可以提升开发效率,快速验证功能稳定性。`Fireyer`的检测项还在不断完善中,后续会持续同步更新。 15 | 16 | 已有的检测项: 17 | 18 | - 签名校验 19 | - 完整性校验 20 | - 属性校验 21 | - 运行内存校验 22 | - 本地数据校验 23 | - `API`权限校验 24 | - `HooK`校验 25 | - 注入校验 26 | 27 | 更详细的检测项,请查看我们的博客文章: [【Fireyer】一款Android平台环境检测应用](https://www.iofomo.com/blog/fireyer) 。 28 | 29 | 如果你也喜欢`Fireyer`,别忘了给我们点个星。 30 | 31 | ## 感谢小伙伴们 32 | 33 | ![](img/thanks.png) 34 | 35 | ## 许可 36 | 37 | This project is licensed under the terms of the `MIT` license. See the [LICENSE](LICENSE) file. 38 | 39 | > This project and all tools are open source under the MIT license, which means you have full access to the source code and can modify it to fit your own needs. 40 | -------------------------------------------------------------------------------- /app/assets/test.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iofomo/fireyer/05b26b41c381a198ddfd7a6f9fa2d6ec694be9f1/app/assets/test.pdf -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply from: '../files/default.gradle' 3 | 4 | android { 5 | def globalConfig = rootProject.extensions.getByName("ext") 6 | buildToolsVersion globalConfig.getAt("androidBuildToolsVersion") 7 | compileSdkVersion globalConfig.getAt("androidCompileSdkVersion") 8 | 9 | defaultConfig { 10 | applicationId "com.ifma.cmpt.demo.fireyer" 11 | minSdkVersion globalConfig.getAt("androidMinSdkVersion") 12 | targetSdkVersion globalConfig.getAt("androidTargetSdkVersion") 13 | versionCode 3 // used in FireyerPackageCase.doCheckApplication(...) 14 | versionName "1.0.3" // used in FireyerPackageCase.doCheckApplication(...) 15 | 16 | testInstrumentationRunner globalConfig.getAt("testInstrumentationRunner") 17 | 18 | javaCompileOptions { 19 | annotationProcessorOptions { 20 | includeCompileClasspath = true 21 | } 22 | } 23 | // ndk { 24 | // abiFilters "armeabi-v7a", "arm64-v8a" 25 | // } 26 | } 27 | 28 | sourceSets { 29 | main { 30 | assets.srcDirs = ['assets'] 31 | jniLibs.srcDirs = ['lib'] 32 | aidl.srcDirs = ['src/main/aidl'] 33 | } 34 | } 35 | 36 | signingConfigs { 37 | debug { 38 | storeFile file('../files/fireyer.keystore') 39 | storePassword 'e99c85dc41111f82f7c3290fc87c42bd' 40 | keyAlias 'ifmafireyer' 41 | keyPassword 'e99c85dc41111f82f7c3290fc87c42bd' 42 | } 43 | release { 44 | storeFile file('../files/fireyer.keystore') 45 | storePassword 'e99c85dc41111f82f7c3290fc87c42bd' 46 | keyAlias 'ifmafireyer' 47 | keyPassword 'e99c85dc41111f82f7c3290fc87c42bd' 48 | } 49 | } 50 | 51 | buildTypes { 52 | debug { 53 | minifyEnabled false 54 | jniDebuggable true 55 | signingConfig signingConfigs.debug 56 | } 57 | release { 58 | minifyEnabled false 59 | signingConfig signingConfigs.release 60 | // proguardFiles getDefaultProguardFile('proguard-android.txt'), '../proguard-rules.pro' 61 | // consumerProguardFiles '../proguard-rules.pro' 62 | } 63 | } 64 | 65 | compileOptions { 66 | sourceCompatibility JavaVersion.VERSION_1_8 67 | targetCompatibility JavaVersion.VERSION_1_8 68 | } 69 | } 70 | 71 | repositories { 72 | flatDir { 73 | dirs '../libs' 74 | } 75 | } 76 | 77 | dependencies { 78 | implementation fileTree(dir: 'libs', include: ['*.jar']) 79 | androidTestImplementation 'androidx.test.ext:junit:1.1.1' 80 | 81 | implementation 'androidx.appcompat:appcompat:1.0.0' 82 | implementation 'androidx.legacy:legacy-support-v4:1.0.0' 83 | implementation 'androidx.startup:startup-runtime:1.0.0' 84 | 85 | // add module depend 86 | implementation project(':cmpt-fireyer') 87 | implementation project(':cmpt-cocollider') 88 | 89 | // add maven depend 90 | implementation (name: 'cmpt-utils', ext: 'aar') 91 | implementation (name: 'cmpt-testin', ext: 'aar') 92 | } 93 | -------------------------------------------------------------------------------- /app/mk.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # @ date: 2020.07.27 17:19 4 | # 5 | 6 | set -u 7 | set -e 8 | 9 | LOCAL_PATH=`pwd` 10 | OUT_PATH=$1 11 | BUILD_TYPE=$2 12 | MODULE_NAME=$3 13 | 14 | # ---------------------------------------------------------------- 15 | # pre 16 | # ---------------------------------------------------------------- 17 | rm -rf libs 18 | if [ -d "$OUT_PATH/libs" ] ; then 19 | cp -rf $OUT_PATH/libs ./ 20 | fi 21 | 22 | # ---------------------------------------------------------------- 23 | # build 24 | # ---------------------------------------------------------------- 25 | cd .. 26 | if [ $BUILD_TYPE = debug ] ; then 27 | ./gradlew :$MODULE_NAME:assembleDebug 28 | else 29 | ./gradlew :$MODULE_NAME:assembleRelease 30 | fi 31 | cd - 32 | 33 | # ---------------------------------------------------------------- 34 | # build end 35 | # ---------------------------------------------------------------- 36 | cp -f $LOCAL_PATH/build/outputs/apk/$BUILD_TYPE/*.apk $OUT_PATH/$MODULE_NAME.apk 37 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 38 | 39 | 40 | 41 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 122 | 123 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 178 | 179 | 180 | 181 | 188 | 189 | 190 | 194 | 195 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | -------------------------------------------------------------------------------- /app/src/main/aidl/android/media/AttributionSourceState.aidl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2021 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package android.media; 18 | 19 | /** 20 | * Payload for the {@link AttributionSource} class needed to interoperate 21 | * with different languages. 22 | * 23 | * {@hide} 24 | */ 25 | parcelable AttributionSourceState { 26 | /** The PID that is accessing the permission protected data. */ 27 | int pid = -1; 28 | /** The UID that is accessing the permission protected data. */ 29 | int uid = -1; 30 | /** The package that is accessing the permission protected data. */ 31 | String packageName; 32 | /** The attribution tag of the app accessing the permission protected data. */ 33 | String attributionTag; 34 | /** Unique token for that source. */ 35 | IBinder token; 36 | /** Permissions that should be considered revoked regardless if granted. */ 37 | String[] renouncedPermissions; 38 | /** The next app to receive the permission protected data. */ 39 | // TODO: We use an array as a workaround - the C++ backend doesn't 40 | // support referring to the parcelable as it expects ctor/dtor 41 | AttributionSourceState[] next; 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/aidl/android/media/AudioAttributesInternal.aidl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package android.media; 18 | 19 | import android.media.AudioContentType; 20 | import android.media.AudioSourceType; 21 | import android.media.AudioUsage; 22 | 23 | /** 24 | * The "Internal" suffix of this type name is to disambiguate it from the 25 | * android.media.AudioAttributes SDK type. 26 | * {@hide} 27 | */ 28 | parcelable AudioAttributesInternal { 29 | AudioContentType contentType; 30 | AudioUsage usage; 31 | AudioSourceType source; 32 | // Bitmask, indexed by AudioFlag. 33 | int flags; 34 | String tags; /* UTF8 */ 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/aidl/android/media/AudioClient.aidl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package android.media; 18 | 19 | import android.media.AttributionSourceState; 20 | 21 | /** 22 | * {@hide} 23 | */ 24 | parcelable AudioClient { 25 | /** Interpreted as pid_t. */ 26 | int clientTid; 27 | AttributionSourceState attributionSource; 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/aidl/android/media/AudioConfigBase.aidl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package android.media; 18 | 19 | import android.media.AudioFormat; 20 | 21 | /** 22 | * {@hide} 23 | */ 24 | parcelable AudioConfigBase { 25 | int sampleRate; 26 | /** Interpreted as audio_channel_mask_t. */ 27 | int channelMask; 28 | AudioFormat format; 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/aidl/android/media/AudioContentType.aidl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package android.media; 17 | 18 | @Backing(type="int") 19 | enum AudioContentType { 20 | UNKNOWN = 0, 21 | SPEECH = 1, 22 | MUSIC = 2, 23 | MOVIE = 3, 24 | SONIFICATION = 4, 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/aidl/android/media/AudioFormat.aidl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2019 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | // This file has been semi-automatically generated using hidl2aidl from its counterpart in 18 | // hardware/interfaces/audio/common/5.0/types.hal 19 | 20 | package android.media; 21 | 22 | /** 23 | * Audio format is a 32-bit word that consists of: 24 | * main format field (upper 8 bits) 25 | * sub format field (lower 24 bits). 26 | * 27 | * The main format indicates the main codec type. The sub format field indicates 28 | * options and parameters for each format. The sub format is mainly used for 29 | * record to indicate for instance the requested bitrate or profile. It can 30 | * also be used for certain formats to give informations not present in the 31 | * encoded audio stream (e.g. octet alignement for AMR). 32 | * 33 | * {@hide} 34 | */ 35 | @Backing(type="int") 36 | enum AudioFormat { 37 | INVALID = 0xFFFFFFFF, 38 | DEFAULT = 0, 39 | PCM = 0x00000000, 40 | MP3 = 0x01000000, 41 | AMR_NB = 0x02000000, 42 | AMR_WB = 0x03000000, 43 | AAC = 0x04000000, 44 | /** 45 | * Deprecated, Use AAC_HE_V1 46 | */ 47 | HE_AAC_V1 = 0x05000000, 48 | /** 49 | * Deprecated, Use AAC_HE_V2 50 | */ 51 | HE_AAC_V2 = 0x06000000, 52 | VORBIS = 0x07000000, 53 | OPUS = 0x08000000, 54 | AC3 = 0x09000000, 55 | E_AC3 = 0x0A000000, 56 | DTS = 0x0B000000, 57 | DTS_HD = 0x0C000000, 58 | /** 59 | * IEC61937 is encoded audio wrapped in 16-bit PCM. 60 | */ 61 | IEC61937 = 0x0D000000, 62 | DOLBY_TRUEHD = 0x0E000000, 63 | EVRC = 0x10000000, 64 | EVRCB = 0x11000000, 65 | EVRCWB = 0x12000000, 66 | EVRCNW = 0x13000000, 67 | AAC_ADIF = 0x14000000, 68 | WMA = 0x15000000, 69 | WMA_PRO = 0x16000000, 70 | AMR_WB_PLUS = 0x17000000, 71 | MP2 = 0x18000000, 72 | QCELP = 0x19000000, 73 | DSD = 0x1A000000, 74 | FLAC = 0x1B000000, 75 | ALAC = 0x1C000000, 76 | APE = 0x1D000000, 77 | AAC_ADTS = 0x1E000000, 78 | SBC = 0x1F000000, 79 | APTX = 0x20000000, 80 | APTX_HD = 0x21000000, 81 | AC4 = 0x22000000, 82 | LDAC = 0x23000000, 83 | /** 84 | * Dolby Metadata-enhanced Audio Transmission 85 | */ 86 | MAT = 0x24000000, 87 | AAC_LATM = 0x25000000, 88 | CELT = 0x26000000, 89 | APTX_ADAPTIVE = 0x27000000, 90 | LHDC = 0x28000000, 91 | LHDC_LL = 0x29000000, 92 | APTX_TWSP = 0x2A000000, 93 | /** 94 | * Deprecated 95 | */ 96 | MAIN_MASK = 0xFF000000, 97 | SUB_MASK = 0x00FFFFFF, 98 | /** 99 | * Subformats 100 | */ 101 | PCM_SUB_16_BIT = 0x1, 102 | PCM_SUB_8_BIT = 0x2, 103 | PCM_SUB_32_BIT = 0x3, 104 | PCM_SUB_8_24_BIT = 0x4, 105 | PCM_SUB_FLOAT = 0x5, 106 | PCM_SUB_24_BIT_PACKED = 0x6, 107 | MP3_SUB_NONE = 0x0, 108 | AMR_SUB_NONE = 0x0, 109 | AAC_SUB_MAIN = 0x1, 110 | AAC_SUB_LC = 0x2, 111 | AAC_SUB_SSR = 0x4, 112 | AAC_SUB_LTP = 0x8, 113 | AAC_SUB_HE_V1 = 0x10, 114 | AAC_SUB_SCALABLE = 0x20, 115 | AAC_SUB_ERLC = 0x40, 116 | AAC_SUB_LD = 0x80, 117 | AAC_SUB_HE_V2 = 0x100, 118 | AAC_SUB_ELD = 0x200, 119 | AAC_SUB_XHE = 0x300, 120 | VORBIS_SUB_NONE = 0x0, 121 | E_AC3_SUB_JOC = 0x1, 122 | MAT_SUB_1_0 = 0x1, 123 | MAT_SUB_2_0 = 0x2, 124 | MAT_SUB_2_1 = 0x3, 125 | // TODO(ytai): Aliases not currently supported in AIDL - can inline the values. 126 | // /** 127 | // * Aliases 128 | // * 129 | // * 130 | // * note != AudioFormat.ENCODING_PCM_16BIT 131 | // */ 132 | // PCM_16_BIT = (PCM | PCM_SUB_16_BIT), 133 | // /** 134 | // * note != AudioFormat.ENCODING_PCM_8BIT 135 | // */ 136 | // PCM_8_BIT = (PCM | PCM_SUB_8_BIT), 137 | // PCM_32_BIT = (PCM | PCM_SUB_32_BIT), 138 | // PCM_8_24_BIT = (PCM | PCM_SUB_8_24_BIT), 139 | // PCM_FLOAT = (PCM | PCM_SUB_FLOAT), 140 | // PCM_24_BIT_PACKED = (PCM | PCM_SUB_24_BIT_PACKED), 141 | // AAC_MAIN = (AAC | AAC_SUB_MAIN), 142 | // AAC_LC = (AAC | AAC_SUB_LC), 143 | // AAC_SSR = (AAC | AAC_SUB_SSR), 144 | // AAC_LTP = (AAC | AAC_SUB_LTP), 145 | // AAC_HE_V1 = (AAC | AAC_SUB_HE_V1), 146 | // AAC_SCALABLE = (AAC | AAC_SUB_SCALABLE), 147 | // AAC_ERLC = (AAC | AAC_SUB_ERLC), 148 | // AAC_LD = (AAC | AAC_SUB_LD), 149 | // AAC_HE_V2 = (AAC | AAC_SUB_HE_V2), 150 | // AAC_ELD = (AAC | AAC_SUB_ELD), 151 | // AAC_XHE = (AAC | AAC_SUB_XHE), 152 | // AAC_ADTS_MAIN = (AAC_ADTS | AAC_SUB_MAIN), 153 | // AAC_ADTS_LC = (AAC_ADTS | AAC_SUB_LC), 154 | // AAC_ADTS_SSR = (AAC_ADTS | AAC_SUB_SSR), 155 | // AAC_ADTS_LTP = (AAC_ADTS | AAC_SUB_LTP), 156 | // AAC_ADTS_HE_V1 = (AAC_ADTS | AAC_SUB_HE_V1), 157 | // AAC_ADTS_SCALABLE = (AAC_ADTS | AAC_SUB_SCALABLE), 158 | // AAC_ADTS_ERLC = (AAC_ADTS | AAC_SUB_ERLC), 159 | // AAC_ADTS_LD = (AAC_ADTS | AAC_SUB_LD), 160 | // AAC_ADTS_HE_V2 = (AAC_ADTS | AAC_SUB_HE_V2), 161 | // AAC_ADTS_ELD = (AAC_ADTS | AAC_SUB_ELD), 162 | // AAC_ADTS_XHE = (AAC_ADTS | AAC_SUB_XHE), 163 | // E_AC3_JOC = (E_AC3 | E_AC3_SUB_JOC), 164 | // MAT_1_0 = (MAT | MAT_SUB_1_0), 165 | // MAT_2_0 = (MAT | MAT_SUB_2_0), 166 | // MAT_2_1 = (MAT | MAT_SUB_2_1), 167 | // AAC_LATM_LC = (AAC_LATM | AAC_SUB_LC), 168 | // AAC_LATM_HE_V1 = (AAC_LATM | AAC_SUB_HE_V1), 169 | // AAC_LATM_HE_V2 = (AAC_LATM | AAC_SUB_HE_V2), 170 | } 171 | -------------------------------------------------------------------------------- /app/src/main/aidl/android/media/AudioSourceType.aidl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package android.media; 17 | 18 | /** 19 | * {@hide} 20 | */ 21 | @Backing(type="int") 22 | enum AudioSourceType { 23 | INVALID = -1, 24 | DEFAULT = 0, 25 | MIC = 1, 26 | VOICE_UPLINK = 2, 27 | VOICE_DOWNLINK = 3, 28 | VOICE_CALL = 4, 29 | CAMCORDER = 5, 30 | VOICE_RECOGNITION = 6, 31 | VOICE_COMMUNICATION = 7, 32 | REMOTE_SUBMIX = 8, 33 | UNPROCESSED = 9, 34 | VOICE_PERFORMANCE = 10, 35 | ECHO_REFERENCE = 1997, 36 | FM_TUNER = 1998, 37 | /** 38 | * A low-priority, preemptible audio source for for background software 39 | * hotword detection. Same tuning as VOICE_RECOGNITION. 40 | * Used only internally by the framework. 41 | */ 42 | HOTWORD = 1999, 43 | } 44 | -------------------------------------------------------------------------------- /app/src/main/aidl/android/media/AudioUsage.aidl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package android.media; 17 | 18 | /** 19 | * {@hide} 20 | */ 21 | @Backing(type="int") 22 | enum AudioUsage { 23 | UNKNOWN = 0, 24 | MEDIA = 1, 25 | VOICE_COMMUNICATION = 2, 26 | VOICE_COMMUNICATION_SIGNALLING = 3, 27 | ALARM = 4, 28 | NOTIFICATION = 5, 29 | NOTIFICATION_TELEPHONY_RINGTONE = 6, 30 | NOTIFICATION_COMMUNICATION_REQUEST = 7, 31 | NOTIFICATION_COMMUNICATION_INSTANT = 8, 32 | NOTIFICATION_COMMUNICATION_DELAYED = 9, 33 | NOTIFICATION_EVENT = 10, 34 | ASSISTANCE_ACCESSIBILITY = 11, 35 | ASSISTANCE_NAVIGATION_GUIDANCE = 12, 36 | ASSISTANCE_SONIFICATION = 13, 37 | GAME = 14, 38 | VIRTUAL_SOURCE = 15, 39 | ASSISTANT = 16, 40 | CALL_ASSISTANT = 17, 41 | EMERGENCY = 1000, 42 | SAFETY = 1001, 43 | VEHICLE_STATUS = 1002, 44 | ANNOUNCEMENT = 1003, 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/aidl/android/media/CreateRecordRequest.aidl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package android.media; 18 | 19 | import android.media.AudioAttributesInternal; 20 | import android.media.AudioClient; 21 | import android.media.AudioConfigBase; 22 | 23 | /** 24 | * CreateRecordRequest contains all input arguments sent by AudioRecord to AudioFlinger 25 | * when calling createRecord() including arguments that will be updated by AudioFlinger 26 | * and returned in CreateRecordResponse object. 27 | * 28 | * {@hide} 29 | */ 30 | parcelable CreateRecordRequest { 31 | AudioAttributesInternal attr; 32 | AudioConfigBase config; 33 | AudioClient clientInfo; 34 | /** Interpreted as audio_unique_id_t. */ 35 | int riid; 36 | int maxSharedAudioHistoryMs; 37 | /** Bitmask, indexed by AudioInputFlags. */ 38 | int flags; 39 | long frameCount; 40 | long notificationFrameCount; 41 | /** Interpreted as audio_port_handle_t. */ 42 | int selectedDeviceId; 43 | int sessionId; 44 | } 45 | -------------------------------------------------------------------------------- /app/src/main/aidl/android/media/CreateRecordResponse.aidl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package android.media; 18 | 19 | import android.media.SharedFileRegion; 20 | 21 | /** 22 | * CreateRecordResponse contains all output arguments returned by AudioFlinger to AudioRecord 23 | * when calling createRecord() including arguments that were passed as I/O for update by 24 | * CreateRecordRequest. 25 | * 26 | * {@hide} 27 | */ 28 | parcelable CreateRecordResponse { 29 | /** Bitmask, indexed by AudioInputFlags. */ 30 | int flags; 31 | long frameCount; 32 | long notificationFrameCount; 33 | /** Interpreted as audio_port_handle_t. */ 34 | int selectedDeviceId; 35 | int sessionId; 36 | int sampleRate; 37 | /** Interpreted as audio_io_handle_t. */ 38 | int inputId; 39 | SharedFileRegion cblk; 40 | SharedFileRegion buffers; 41 | /** Interpreted as audio_port_handle_t. */ 42 | int portId; 43 | /** The newly created record. */ 44 | IBinder audioRecord; 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/aidl/android/media/SharedFileRegion.aidl: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020 The Android Open Source Project 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package android.media; 18 | 19 | /** 20 | * A shared file region. 21 | * 22 | * This type contains the required information to share a region of a file between processes over 23 | * AIDL. 24 | * An instance of this type represents a valid FD. For representing a null SharedFileRegion, use a 25 | * @nullable SharedFileRegion. 26 | * Primarily, this is intended for shared memory blocks. 27 | * 28 | * @hide 29 | */ 30 | parcelable SharedFileRegion { 31 | /** File descriptor of the region. Must be valid. */ 32 | ParcelFileDescriptor fd; 33 | /** Offset, in bytes within the file of the start of the region. Must be non-negative. */ 34 | long offset; 35 | /** Size, in bytes of the memory region. Must be non-negative. */ 36 | long size; 37 | /** Whether the region is writeable. */ 38 | boolean writeable; 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/aidl/com/ifma/cmpt/demo/IBinderTest.aidl: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.demo; 2 | 3 | import android.media.CreateRecordResponse; 4 | import android.media.CreateRecordRequest; 5 | 6 | interface IBinderTest { 7 | int callBinderTest1(String a, IBinder c, int d); 8 | int callBinderTest2(int a, IBinder b, String c); 9 | int callBinderTest(String a, String b, IBinder c, int d, String e, IBinder f, String g); 10 | CreateRecordResponse createRecord(in CreateRecordRequest request); 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/aidl/com/ifma/cmpt/demo/IBinderTestCallback.aidl: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.demo; 2 | 3 | interface IBinderTestCallback { 4 | int handleBinderTestCallback(int a); 5 | } 6 | -------------------------------------------------------------------------------- /app/src/main/java/com/ifma/cmpt/demo/DemoApplication.java: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.demo; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | 6 | import com.ifma.cmpt.demo.main.MainReceiver; 7 | import com.ifma.cmpt.demo.module.LauncherMonitor; 8 | import com.ifma.cmpt.demo.test.FireyerRuntimeCase; 9 | import com.ifma.cmpt.demo.test.FireyerStackCase; 10 | import com.ifma.cmpt.fireyer.FireyerManager; 11 | import com.ifma.cmpt.testin.env.TstEnv; 12 | import com.ifma.cmpt.utils.ReflectUtils; 13 | 14 | public class DemoApplication extends Application { 15 | private final static String TAG = "DemoApplication"; 16 | 17 | @Override 18 | protected void attachBaseContext(Context base) { 19 | super.attachBaseContext(base); 20 | FireyerRuntimeCase.sDemoApplicationABC = true; 21 | FireyerRuntimeCase.sHiddenApi = FireyerManager.checkHiddenAPI(); 22 | FireyerStackCase.dumpStackForApplication_attachBaseContext(); 23 | TstEnv.init(this); 24 | MainReceiver.register(base); 25 | // dumpClassLoader(getClassLoader()); 26 | LauncherMonitor.init(); 27 | 28 | clearServiceManager(); 29 | // TstClassPrinter.printStub("android.content.IContentProvider"); 30 | // TstClassPrinter.printStubByCodes("android.content.pm.IPackageManager", 179); 31 | } 32 | 33 | public static void clearServiceManager() { 34 | Class cls = ReflectUtils.findClass("android.os.ServiceManager"); 35 | ReflectUtils.setStaticFieldValue(cls, "sServiceManager", null); 36 | } 37 | 38 | @Override 39 | public void onCreate() { 40 | super.onCreate(); 41 | FireyerRuntimeCase.sDemoApplicationCreate = true; 42 | FireyerStackCase.dumpStackForApplication_onCreate(); 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /app/src/main/java/com/ifma/cmpt/demo/DemoComponentFactory.java: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.demo; 2 | 3 | import android.app.Activity; 4 | import android.app.AppComponentFactory; 5 | import android.app.Application; 6 | import android.app.Service; 7 | import android.content.BroadcastReceiver; 8 | import android.content.ContentProvider; 9 | import android.content.Intent; 10 | import android.content.pm.ApplicationInfo; 11 | import android.text.TextUtils; 12 | 13 | import com.ifma.cmpt.demo.test.FireyerPackageCase; 14 | import com.ifma.cmpt.demo.test.FireyerRuntimeCase; 15 | import com.ifma.cmpt.demo.test.FireyerStackCase; 16 | import com.ifma.cmpt.testin.module.TstRunner; 17 | 18 | public class DemoComponentFactory extends AppComponentFactory { 19 | 20 | public ClassLoader instantiateClassLoader(ClassLoader cl, ApplicationInfo aInfo) { 21 | FireyerRuntimeCase.sAppComponentFactoryInitClass = true; 22 | FireyerPackageCase.doCheckApplicationInfo("ACF ", aInfo); 23 | FireyerPackageCase.dumpPackageInfo(aInfo); 24 | FireyerStackCase.dumpStackForInstantiateClassLoader(); 25 | return cl; 26 | } 27 | 28 | public Application instantiateApplication(ClassLoader cl, String className) 29 | throws InstantiationException, IllegalAccessException, ClassNotFoundException { 30 | FireyerRuntimeCase.sAppComponentFactoryInitApp = true; 31 | FireyerStackCase.dumpStackForInstantiateApplication(); 32 | TstRunner.print("instantiateApplication", "com.ifma.cmpt.demo.FakeApplication".equals(className)); 33 | return (Application) cl.loadClass("com.ifma.cmpt.demo.DemoApplication").newInstance(); 34 | } 35 | 36 | public Activity instantiateActivity(ClassLoader cl, String className, Intent intent) 37 | throws InstantiationException, IllegalAccessException, ClassNotFoundException { 38 | FireyerRuntimeCase.sAppComponentFactoryInitActivity = true; 39 | FireyerStackCase.dumpStackForInstantiateActivity(); 40 | TstRunner.print("instantiateActivity", 41 | TextUtils.equals("com.ifma.cmpt.demo.main.MainActivity", className) || 42 | TextUtils.equals("com.ifma.cmpt.demo.main.ConsoleActivity", className) || 43 | TextUtils.equals("com.ifma.cmpt.demo.sub.SubActivity", className) 44 | ); 45 | return (Activity) cl.loadClass(className).newInstance(); 46 | } 47 | 48 | public BroadcastReceiver instantiateReceiver(ClassLoader cl, String className, Intent intent) 49 | throws InstantiationException, IllegalAccessException, ClassNotFoundException { 50 | TstRunner.print("instantiateReceiver", 51 | TextUtils.equals("com.ifma.cmpt.demo.main.MainReceiver", className) || 52 | TextUtils.equals("com.ifma.cmpt.demo.sub.SubReceiver", className) 53 | ); 54 | return (BroadcastReceiver) cl.loadClass(className).newInstance(); 55 | } 56 | 57 | public Service instantiateService(ClassLoader cl, String className, Intent intent) 58 | throws InstantiationException, IllegalAccessException, ClassNotFoundException { 59 | TstRunner.print("instantiateService", 60 | TextUtils.equals("com.ifma.cmpt.demo.main.MainService", className) || 61 | TextUtils.equals("com.ifma.cmpt.demo.sub.SubService", className) 62 | ); 63 | return (Service) cl.loadClass(className).newInstance(); 64 | } 65 | 66 | public ContentProvider instantiateProvider(ClassLoader cl, String className) 67 | throws InstantiationException, IllegalAccessException, ClassNotFoundException { 68 | FireyerRuntimeCase.sAppComponentFactoryInitProvider = true; 69 | TstRunner.print("instantiateProvider", 70 | TextUtils.equals("com.ifma.cmpt.demo.main.MainProvider", className) || 71 | TextUtils.equals("com.ifma.cmpt.demo.sub.SubProvider", className) || 72 | TextUtils.equals("com.ifma.cmpt.demo.sub.SubPermissionProvider", className) || 73 | TextUtils.equals("androidx.startup.InitializationProvider", className) 74 | ); 75 | FireyerStackCase.dumpStackForInstantiateProvider(); 76 | return (ContentProvider) cl.loadClass(className).newInstance(); 77 | } 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/com/ifma/cmpt/demo/FakeApplication.java: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.demo; 2 | 3 | import android.app.Application; 4 | import android.content.Context; 5 | 6 | import com.ifma.cmpt.demo.test.FireyerRuntimeCase; 7 | 8 | public class FakeApplication extends Application { 9 | 10 | @Override 11 | protected void attachBaseContext(Context base) { 12 | super.attachBaseContext(base); 13 | FireyerRuntimeCase.sFakeApplicationABC = false; 14 | } 15 | 16 | @Override 17 | public void onCreate() { 18 | super.onCreate(); 19 | FireyerRuntimeCase.sFakeApplicationCreate = false; 20 | } 21 | 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/ifma/cmpt/demo/NativeCall.java: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.demo; 2 | 3 | public class NativeCall { 4 | static { 5 | try { 6 | System.loadLibrary("fireyer-jni"); 7 | } catch (Throwable e) { 8 | e.printStackTrace(); 9 | } 10 | } 11 | 12 | public native Object callNative(int i, Object args); 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/ifma/cmpt/demo/main/ConsoleActivity.java: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.demo.main; 2 | 3 | import android.app.Activity; 4 | import android.app.AlertDialog; 5 | import android.content.BroadcastReceiver; 6 | import android.content.DialogInterface; 7 | import android.graphics.Color; 8 | import android.os.Bundle; 9 | import android.os.Handler; 10 | import android.text.SpannableStringBuilder; 11 | import android.text.Spanned; 12 | import android.text.TextUtils; 13 | import android.text.method.ScrollingMovementMethod; 14 | import android.text.style.ForegroundColorSpan; 15 | import android.view.LayoutInflater; 16 | import android.view.View; 17 | import android.view.WindowManager; 18 | import android.widget.EditText; 19 | import android.widget.ScrollView; 20 | import android.widget.TextView; 21 | 22 | import com.ifma.cmpt.demo.fireyer.R; 23 | import com.ifma.cmpt.demo.module.ClipboadData; 24 | import com.ifma.cmpt.demo.test.FireyerCaseConsts; 25 | import com.ifma.cmpt.demo.test.FireyerPackageCase; 26 | import com.ifma.cmpt.demo.test.FireyerRuntimeCase; 27 | import com.ifma.cmpt.testin.env.TstConsts; 28 | import com.ifma.cmpt.testin.env.TstHandler; 29 | import com.ifma.cmpt.testin.module.TstRunner; 30 | 31 | import java.util.List; 32 | import java.util.concurrent.CopyOnWriteArrayList; 33 | 34 | public class ConsoleActivity extends Activity { 35 | private TextView mTextConsole; 36 | private ScrollView mScrollView; 37 | protected BroadcastReceiver mBR; 38 | private Handler mHandler = null; 39 | 40 | @Override 41 | public void onCreate(Bundle savedInstanceState) { 42 | super.onCreate(savedInstanceState); 43 | setContentView(R.layout.activity_console); 44 | initView(); 45 | initData(); 46 | 47 | if (FireyerCaseConsts.isVirtualMode()) { 48 | showInputDialog();// got info from clipboard 49 | } else { 50 | initTest(); 51 | } 52 | } 53 | 54 | protected void initView() { 55 | mHandler = new Handler(); 56 | mTextConsole = (TextView) findViewById(R.id.console); 57 | mScrollView = (ScrollView) findViewById(R.id.scrollView); 58 | mTextConsole.setMovementMethod(ScrollingMovementMethod.getInstance()); 59 | } 60 | 61 | protected void initData() { 62 | addMessage("Console started ..."); 63 | if (FireyerCaseConsts.isSourceMode()) { 64 | addMessage("From source env"); 65 | } else if (FireyerCaseConsts.isKonkerMode()) { 66 | addMessage("From konker env"); 67 | } else if (FireyerCaseConsts.isPackerMode()) { 68 | addMessage("From packer env"); 69 | } 70 | } 71 | 72 | protected void initTest() { 73 | final Bundle args = getIntent().getExtras(); 74 | if (!TextUtils.equals(TstConsts.VALUE_UNITTEST, args.getString(TstConsts.KEY_TYPE))) return; 75 | 76 | TstRunner.runTest(args, new TstRunner.ITstPrinter() { 77 | @Override 78 | public void onTstStart() { 79 | if (FireyerCaseConsts.isVirtualMode()) { 80 | int cnt = ClipboadData.loadFromClipboard(getApplicationContext()); 81 | addMessage("Load info from Clipboard: " + cnt); 82 | } else { 83 | FireyerRuntimeCase.dumpThread(); 84 | FireyerPackageCase.dumpApk(getApplicationContext()); 85 | } 86 | } 87 | 88 | @Override 89 | public void onTstDone() { 90 | if (FireyerCaseConsts.isSourceMode()) { 91 | mHandler.postDelayed(new Runnable() { 92 | @Override 93 | public void run() { 94 | showInputDialog(); 95 | } 96 | }, 1000); 97 | } 98 | addMessage("[Info] passed " + TstRunner.getPassedCaseCount() + " cases"); 99 | addMessage("[Info] failed " + TstRunner.getFailedCaseCount() + " cases"); 100 | } 101 | 102 | @Override 103 | public void onTstPrint(String s) { 104 | addMessage(s); 105 | } 106 | }); 107 | } 108 | 109 | private final List mMsgList = new CopyOnWriteArrayList<>(); 110 | 111 | private Runnable mMsgRunner = new Runnable() { 112 | @Override 113 | public void run() { 114 | doPrint(); 115 | } 116 | }; 117 | 118 | protected void addMessage(String msg) { 119 | mMsgList.add(msg); 120 | if (TstHandler.isMainThread()) { 121 | doPrint(); 122 | } else { 123 | TstHandler.postUi(mMsgRunner); 124 | } 125 | } 126 | 127 | public static final String TEXT_PRE_OK = "[O"; 128 | public static final String TEXT_PRE_FAIL = "[F"; 129 | public static final String TEXT_PRE_ERROR = "[E"; 130 | public static final String TEXT_PRE_WARN = "[W"; 131 | public static final String TEXT_PRE_INFO = "[I"; 132 | 133 | private synchronized void doPrint() { 134 | while (!mMsgList.isEmpty()) { 135 | doPrint(mMsgList.remove(0)); 136 | } 137 | } 138 | 139 | private void doPrint(String msg) { 140 | if (TextUtils.isEmpty(msg)) { 141 | mTextConsole.append("\n"); 142 | return; 143 | } 144 | try { 145 | SpannableStringBuilder builder = new SpannableStringBuilder(msg); 146 | if (msg.startsWith(TEXT_PRE_OK)) { 147 | builder.setSpan(new ForegroundColorSpan(0xAA00FF00), 0, msg.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 148 | } else if (msg.startsWith(TEXT_PRE_FAIL) || msg.startsWith(TEXT_PRE_ERROR)) { 149 | builder.setSpan(new ForegroundColorSpan(0xAAFF0000), 0, msg.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 150 | } else if (msg.startsWith(TEXT_PRE_WARN)) { 151 | builder.setSpan(new ForegroundColorSpan(Color.YELLOW), 0, msg.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 152 | } else if (msg.startsWith(TEXT_PRE_INFO)) { 153 | builder.setSpan(new ForegroundColorSpan(Color.WHITE), 0, msg.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 154 | } else { 155 | builder.setSpan(new ForegroundColorSpan(0xAA000000), 0, msg.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE); 156 | } 157 | mTextConsole.append(builder); 158 | mTextConsole.append("\n"); 159 | int offset = mTextConsole.getMeasuredHeight() - mScrollView.getMeasuredHeight(); 160 | if (offset < 0) { 161 | mScrollView.scrollTo(0, 0); 162 | } else { 163 | mScrollView.scrollTo(0, offset); 164 | } 165 | } catch (Throwable e) { 166 | e.printStackTrace(); 167 | } 168 | } 169 | 170 | protected void onDestroy() { 171 | if (null != mBR) { 172 | try { 173 | unregisterReceiver(mBR); 174 | } catch (Throwable e) { 175 | e.printStackTrace(); 176 | } finally { 177 | mBR = null; 178 | } 179 | } 180 | TstRunner.cancel(); 181 | super.onDestroy(); 182 | } 183 | 184 | private void showInputDialog() { 185 | LayoutInflater inflater = LayoutInflater.from(this); 186 | final View dialogView = inflater.inflate(R.layout.dialog_input, null); 187 | final EditText editText = dialogView.findViewById(R.id.editText); 188 | 189 | final AlertDialog dialog = new AlertDialog.Builder(this) 190 | .setTitle("Got Focus") 191 | .setView(dialogView) 192 | .create(); 193 | 194 | dialog.setOnShowListener(new DialogInterface.OnShowListener() { 195 | @Override 196 | public void onShow(DialogInterface dialogInterface) { 197 | editText.requestFocus(); 198 | dialog.getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE); 199 | 200 | mHandler.postDelayed(new Runnable() { 201 | @Override 202 | public void run() { 203 | if (FireyerCaseConsts.isVirtualMode()) { 204 | ClipboadData.loadFromClipboard(getApplicationContext()); 205 | initTest();// got info, then start to test 206 | } else { 207 | ClipboadData.saveToClipboard(getApplicationContext()); 208 | } 209 | if (dialog.isShowing()) { 210 | dialog.dismiss(); 211 | } 212 | } 213 | }, 1000); 214 | } 215 | }); 216 | 217 | dialog.show(); 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /app/src/main/java/com/ifma/cmpt/demo/main/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.demo.main; 2 | 3 | import android.app.Activity; 4 | import android.app.PendingIntent; 5 | import android.content.BroadcastReceiver; 6 | import android.content.Context; 7 | import android.content.Intent; 8 | import android.content.IntentFilter; 9 | import android.hardware.usb.UsbAccessory; 10 | import android.hardware.usb.UsbDevice; 11 | import android.hardware.usb.UsbManager; 12 | import android.net.Uri; 13 | import android.os.Bundle; 14 | import android.view.View; 15 | import android.widget.TextView; 16 | import android.widget.Toast; 17 | 18 | import androidx.core.content.FileProvider; 19 | 20 | import com.ifma.cmpt.demo.fireyer.BuildConfig; 21 | import com.ifma.cmpt.demo.fireyer.R; 22 | import com.ifma.cmpt.demo.test.FireyerCaseConsts; 23 | import com.ifma.cmpt.demo.test.FireyerStackCase; 24 | import com.ifma.cmpt.testin.env.TstConsts; 25 | import com.ifma.cmpt.testin.module.TstPermissionGrantor; 26 | import com.ifma.cmpt.utils.AssetsUtils; 27 | 28 | import java.io.File; 29 | import java.util.HashMap; 30 | import java.util.Iterator; 31 | //import com.ifma.cmpt.fireyer.FireyerNative; 32 | 33 | 34 | public class MainActivity extends Activity implements View.OnClickListener { 35 | private static final String TAG = "MainActivity"; 36 | 37 | @Override 38 | public void onCreate(Bundle savedInstanceState) { 39 | FireyerStackCase.dumpStackForActivity_onCreate(); 40 | super.onCreate(savedInstanceState); 41 | setContentView(R.layout.activity_main); 42 | initView(); 43 | TstPermissionGrantor.grant(this); 44 | initData(); 45 | } 46 | 47 | private void initView() { 48 | TextView text = (TextView) findViewById(R.id.main_version); 49 | text.setText("v" + BuildConfig.VERSION_NAME + "(" + BuildConfig.VERSION_CODE + ")"); 50 | View v; 51 | v = findViewById(R.id.item_unittest_source); 52 | // v.setVisibility(View.GONE); 53 | v.setOnClickListener(this); 54 | 55 | v = findViewById(R.id.item_unittest_konker); 56 | // v.setVisibility(View.GONE); 57 | v.setOnClickListener(this); 58 | 59 | v = findViewById(R.id.item_shared); 60 | // v.setVisibility(View.GONE); 61 | v.setOnClickListener(this); 62 | } 63 | 64 | public void onClick(View v) { 65 | switch (v.getId()) { 66 | case R.id.item_unittest_source: 67 | { 68 | FireyerCaseConsts.setMode(FireyerCaseConsts.MODE_SOURCE); 69 | Intent i = new Intent(this, ConsoleActivity.class); 70 | i.putExtra(TstConsts.KEY_TYPE, TstConsts.VALUE_UNITTEST); 71 | startActivity(i); 72 | } break; 73 | case R.id.item_unittest_konker: 74 | { 75 | FireyerCaseConsts.setMode(FireyerCaseConsts.MODE_KONKER); 76 | Intent i = new Intent(this, ConsoleActivity.class); 77 | i.putExtra(TstConsts.KEY_TYPE, TstConsts.VALUE_UNITTEST); 78 | startActivity(i); 79 | } break; 80 | case R.id.item_shared: 81 | { 82 | File file = new File(getExternalCacheDir(), "test.pdf"); 83 | if (AssetsUtils.copyAsset(getApplicationContext(), "test.pdf", file.getAbsolutePath())) { 84 | openFileWithInstalledApps(getApplicationContext(), file, "application/pdf"); 85 | } else { 86 | Toast.makeText(getApplicationContext(), "test.pdf export fail", Toast.LENGTH_SHORT).show(); 87 | } 88 | } break; 89 | default: break; 90 | } 91 | } 92 | 93 | public void openFileWithInstalledApps(Context context, File file, String mimeType) { 94 | Uri uri = FileProvider.getUriForFile(context, context.getPackageName() + ".SubProvider", file); 95 | Intent intent = new Intent(Intent.ACTION_VIEW); 96 | intent.setDataAndType(uri, mimeType); 97 | intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION|Intent.FLAG_ACTIVITY_NEW_TASK); 98 | context.startActivity(intent); 99 | } 100 | 101 | private void initData() { 102 | initUsbPermission(); 103 | // TstHandler.post(new Runnable() { 104 | // @Override 105 | // public void run() { 106 | // } 107 | // }); 108 | } 109 | 110 | private static final String ACTION_USB_PERMISSION_DEVICE = "com.ifma.cmpt.demo.fireyer.USB_PERMISSION_DEVICE"; 111 | private static final String ACTION_USB_PERMISSION_ACCESSORY = "com.ifma.cmpt.demo.fireyer.USB_PERMISSION_ACCESSORY"; 112 | 113 | protected void initUsbPermission() { 114 | IntentFilter filter = new IntentFilter(); 115 | filter.addAction(ACTION_USB_PERMISSION_DEVICE); 116 | filter.addAction(ACTION_USB_PERMISSION_ACCESSORY); 117 | registerReceiver(usbReceiver, filter); 118 | 119 | PendingIntent intent = PendingIntent.getBroadcast(this, 0, 120 | new Intent(ACTION_USB_PERMISSION_DEVICE), 0 121 | ); 122 | 123 | UsbManager usbManager = (UsbManager) getSystemService(Context.USB_SERVICE); 124 | HashMap deviceList = usbManager.getDeviceList(); 125 | if (null != deviceList && 0 < deviceList.size()) { 126 | Iterator deviceIterator = deviceList.values().iterator(); 127 | while (deviceIterator.hasNext()) { 128 | UsbDevice device = deviceIterator.next(); 129 | boolean has = usbManager.hasPermission(device); 130 | Toast.makeText(getApplicationContext(), "usb-dev-pmt: " + has, Toast.LENGTH_SHORT).show(); 131 | if (!has) { 132 | usbManager.requestPermission(device, intent); 133 | } 134 | } 135 | } 136 | 137 | intent = PendingIntent.getBroadcast(this, 0, 138 | new Intent(ACTION_USB_PERMISSION_ACCESSORY), 0 139 | ); 140 | UsbAccessory[] accs = usbManager.getAccessoryList(); 141 | if (null != accs && 0 < accs.length) { 142 | for (UsbAccessory acc: accs) { 143 | boolean has = usbManager.hasPermission(acc); 144 | Toast.makeText(getApplicationContext(), "usb-acc-pmt: " + has, Toast.LENGTH_SHORT).show(); 145 | if (!has) { 146 | usbManager.requestPermission(acc, intent); 147 | } 148 | } 149 | } 150 | } 151 | 152 | private final BroadcastReceiver usbReceiver = new BroadcastReceiver() { 153 | public void onReceive(Context context, Intent intent) { 154 | String action = intent.getAction(); 155 | if (ACTION_USB_PERMISSION_DEVICE.equals(action)) { 156 | UsbDevice dev = (UsbDevice) intent.getParcelableExtra(UsbManager.EXTRA_DEVICE); 157 | if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { 158 | Toast.makeText(getApplicationContext(), "usb-dev: " + dev.getSerialNumber(), Toast.LENGTH_SHORT).show(); 159 | } else { 160 | Toast.makeText(getApplicationContext(), "usb-dev: fail", Toast.LENGTH_SHORT).show(); 161 | } 162 | } else if (ACTION_USB_PERMISSION_ACCESSORY.equals(action)) { 163 | UsbAccessory acc = (UsbAccessory) intent.getParcelableExtra(UsbManager.EXTRA_ACCESSORY); 164 | if (intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false)) { 165 | Toast.makeText(getApplicationContext(), "usb-acc: " + acc.getSerial(), Toast.LENGTH_SHORT).show(); 166 | } else { 167 | Toast.makeText(getApplicationContext(), "usb-dev: fail", Toast.LENGTH_SHORT).show(); 168 | } 169 | } 170 | } 171 | }; 172 | 173 | protected void onDestroy() { 174 | unregisterReceiver(usbReceiver); 175 | super.onDestroy(); 176 | } 177 | 178 | } 179 | -------------------------------------------------------------------------------- /app/src/main/java/com/ifma/cmpt/demo/main/MainProvider.java: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.demo.main; 2 | 3 | import com.ifma.cmpt.cocollider.CoColliderManager; 4 | import com.ifma.cmpt.demo.module.ClassDumper; 5 | import com.ifma.cmpt.demo.module.Consts; 6 | import com.ifma.cmpt.demo.module.PackageDumper; 7 | import com.ifma.cmpt.demo.test.FireyerStackCase; 8 | import com.ifma.cmpt.testin.env.TstLogger; 9 | import android.content.ContentProvider; 10 | import android.content.ContentValues; 11 | import android.database.Cursor; 12 | import android.net.Uri; 13 | import android.os.Bundle; 14 | import android.text.TextUtils; 15 | 16 | 17 | public class MainProvider extends ContentProvider { 18 | private static final String TAG = MainProvider.class.getSimpleName(); 19 | 20 | @Override 21 | public boolean onCreate() { 22 | FireyerStackCase.dumpStackForProvider_onCreate(); 23 | TstLogger.e(TAG, "onCreate"); 24 | getContext().getExternalCacheDir(); 25 | return false; 26 | } 27 | 28 | @Override 29 | public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { 30 | TstLogger.e(TAG, "query"); 31 | return null; 32 | } 33 | 34 | @Override 35 | public String getType(Uri uri) { 36 | TstLogger.e(TAG, "getType"); 37 | return "MainProvider"; 38 | } 39 | 40 | @Override 41 | public Uri insert(Uri uri, ContentValues values) { 42 | TstLogger.e(TAG, "insert"); 43 | return null; 44 | } 45 | 46 | @Override 47 | public int delete(Uri uri, String selection, String[] selectionArgs) { 48 | TstLogger.e(TAG, "delete"); 49 | return 0; 50 | } 51 | 52 | @Override 53 | public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 54 | TstLogger.e(TAG, "update"); 55 | return 0; 56 | } 57 | 58 | public Bundle call(String authority, String method, String arg, Bundle extras) { 59 | Bundle replyData = new Bundle(); 60 | try { 61 | switch (method) { 62 | case "dump": 63 | handleDumpEvent(arg, extras, replyData); 64 | break; 65 | case "method":// for test case 66 | handleTestCaseEvent(authority, arg, extras, replyData); 67 | break; 68 | case "coco": 69 | CoColliderManager.handleCallEvent(getContext(), extras, replyData); 70 | break; 71 | default: break; 72 | } 73 | } catch (Throwable e) { 74 | e.printStackTrace(); 75 | replyData.putInt(Consts.KEY_CODE, -9); 76 | replyData.putString(Consts.KEY_MSG, e.getMessage()); 77 | } 78 | return replyData; 79 | } 80 | 81 | private void handleDumpEvent(String type, Bundle inData, Bundle replyData) throws Throwable { 82 | switch (type) { 83 | case "class": 84 | ClassDumper.handleCallEvent(getContext(), inData, replyData); 85 | break; 86 | case "pkg": 87 | PackageDumper.handleCallEvent(getContext(), inData, replyData); 88 | break; 89 | default: break; 90 | } 91 | } 92 | 93 | private void handleTestCaseEvent(String authority, String arg, Bundle extras, Bundle replyData) { 94 | boolean succ = false; 95 | do { 96 | if (!TextUtils.equals(authority, "com.ifma.cmpt.demo.fireyer.MainProvider")) break; 97 | if (!TextUtils.equals(arg, "arg")) break; 98 | if (1 != extras.size()) break; 99 | if (100 != extras.getInt("call")) break; 100 | succ = true; 101 | } while (false); 102 | replyData.putBoolean("call", succ); 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /app/src/main/java/com/ifma/cmpt/demo/main/MainReceiver.java: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.demo.main; 2 | 3 | import com.ifma.cmpt.testin.env.TstConsts; 4 | import com.ifma.cmpt.testin.env.TstLogger; 5 | import android.content.BroadcastReceiver; 6 | import android.content.Context; 7 | import android.content.Intent; 8 | import android.content.IntentFilter; 9 | 10 | 11 | public class MainReceiver extends BroadcastReceiver { 12 | private static final String TAG = MainReceiver.class.getSimpleName(); 13 | 14 | public static void register(Context ctx) { 15 | ctx.registerReceiver(new MainReceiver(), new IntentFilter(TstConsts.getActionReceiver())); 16 | } 17 | 18 | @Override 19 | public void onReceive(Context context, Intent intent) { 20 | TstLogger.bundle(TAG, intent.getExtras()); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/ifma/cmpt/demo/main/MainService.java: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.demo.main; 2 | 3 | import android.app.Service; 4 | 5 | import com.ifma.cmpt.testin.env.TstHandler; 6 | import com.ifma.cmpt.testin.env.TstLogger; 7 | import com.ifma.cmpt.utils.Logger; 8 | import com.ifma.cmpt.utils.MessengerUtils; 9 | 10 | import android.content.Intent; 11 | import android.os.Bundle; 12 | import android.os.IBinder; 13 | import android.os.Message; 14 | 15 | public class MainService extends Service implements MessengerUtils.IServiceCallback { 16 | private static final String TAG = MainService.class.getSimpleName(); 17 | 18 | private MessengerUtils.ServiceMessenger mMessenger; 19 | public void onCreate() { 20 | super.onCreate(); 21 | mMessenger = new MessengerUtils.ServiceMessenger(this, TstHandler.getLooper()); 22 | } 23 | 24 | @Override 25 | public Message handleMessage(Message msg) { 26 | if (Logger.D) Logger.d(TAG, "handleMessage: " + msg.toString()); 27 | 28 | final Bundle inData = msg.getData(); 29 | final Bundle replyData = new Bundle(); 30 | do { 31 | if (msg.what != inData.getInt("msg")) break; 32 | if (1 != inData.size()) break; 33 | replyData.putInt("call", msg.what); 34 | } while (false); 35 | 36 | Message outMessage = Message.obtain(null, msg.what); 37 | outMessage.setData(replyData); 38 | return outMessage; 39 | } 40 | 41 | @Override 42 | public IBinder onBind(Intent intent) { 43 | return mMessenger.getBinder(); 44 | } 45 | 46 | @Override 47 | public void onDestroy() { 48 | super.onDestroy(); 49 | } 50 | 51 | @Override 52 | public int onStartCommand(Intent intent, int flags, int startId) { 53 | TstLogger.d(TAG, intent.toString()); 54 | return START_NOT_STICKY; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /app/src/main/java/com/ifma/cmpt/demo/module/ClassDumper.java: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.demo.module; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.text.TextUtils; 6 | 7 | import com.ifma.cmpt.testin.utils.TstClassPrinter; 8 | import com.ifma.cmpt.utils.FileUtils; 9 | import com.ifma.cmpt.utils.Logger; 10 | 11 | import java.io.File; 12 | import java.io.FileOutputStream; 13 | import java.io.OutputStream; 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | public class ClassDumper { 18 | private static final String TAG = "ClassDumper"; 19 | 20 | public static void handleCallEvent(Context ctx, Bundle inData, Bundle replyData) { 21 | final String fileOrClass = inData.getString(Consts.KEY_IN_ARG1); 22 | final String outPath = inData.getString(Consts.KEY_IN_ARG2); 23 | final String mode = inData.getString(Consts.KEY_IN_ARG3); 24 | 25 | int failCnt; 26 | if (fileOrClass.startsWith("/") || fileOrClass.startsWith("\\")) { 27 | List lines = FileUtils.readLines(new File(fileOrClass)); 28 | if (null == lines) { 29 | replyData.putInt(Consts.KEY_CODE, -1); 30 | replyData.putString(Consts.KEY_MSG, "Error: file not found " + fileOrClass); 31 | return; 32 | } 33 | if (lines.isEmpty()) { 34 | replyData.putInt(Consts.KEY_CODE, -2); 35 | replyData.putString(Consts.KEY_MSG, "Error: empty file"); 36 | return; 37 | } 38 | failCnt = doParse(lines, outPath, mode); 39 | } else { 40 | failCnt = doParseClass(fileOrClass, outPath, mode) ? 0 : 1; 41 | } 42 | if (failCnt == 0) { 43 | replyData.putInt(Consts.KEY_CODE, 0); 44 | replyData.putString(Consts.KEY_MSG, "success"); 45 | } else { 46 | replyData.putInt(Consts.KEY_CODE, failCnt); 47 | replyData.putString(Consts.KEY_MSG, "Error: " + failCnt + " class dump fail"); 48 | } 49 | } 50 | private static final String TARGET_PRE = "target,"; 51 | private static final String ONEWAY_PRE = "oneway,"; 52 | public static int doParse(List lines, String outPath, String mode) { 53 | int failCnt = 0; 54 | for (String line : lines) { 55 | if (line.startsWith(TARGET_PRE)) { 56 | line = line.substring(TARGET_PRE.length()); 57 | int pos = line.indexOf(','); 58 | if (!doParseClass(line.substring(pos+1), outPath, mode)) { 59 | failCnt += 1; 60 | } 61 | } else if (line.startsWith(ONEWAY_PRE)) { 62 | line = line.substring(TARGET_PRE.length()); 63 | int pos = line.indexOf(','); 64 | if (!doParseClass(line.substring(pos+1), outPath, mode)) { 65 | failCnt += 1; 66 | } 67 | } 68 | } 69 | return failCnt; 70 | } 71 | 72 | private static boolean doParseClass(String classLine, String outPath, String mode) { 73 | List targetValues = new ArrayList(); 74 | String[] items = classLine.split(","); 75 | if (!TextUtils.equals(mode, "all")) { 76 | if (null != items && items.length >= 2) { 77 | for (int i = 1; i < items.length; ++i) { 78 | targetValues.add(Integer.valueOf(items[i])); 79 | } 80 | } 81 | } 82 | 83 | int pos = items[0].lastIndexOf('.'); 84 | String pathName = 0 < pos ? items[0].substring(0, pos) : ""; 85 | String className = 0 < pos ? items[0].substring(pos+1) : items[0]; 86 | 87 | OutputStream os = null; 88 | File file = new File(outPath + File.separator + className + ".java"); 89 | FileUtils.mkParentDirs(file); 90 | try { 91 | os = new FileOutputStream(file); 92 | DumperWriter writer = new DumperWriter(pathName, className, os); 93 | TstClassPrinter.setCallback(writer); 94 | 95 | if (targetValues.isEmpty()) { 96 | TstClassPrinter.printStub(items[0]); 97 | } else { 98 | TstClassPrinter.printStub(items[0], targetValues); 99 | } 100 | if (0 < writer.getCount()) { 101 | writer.writeTailer(); 102 | return true; 103 | } 104 | 105 | DumperInfoWriter infoWriter = new DumperInfoWriter(os); 106 | TstClassPrinter.printClass(items[0], true, infoWriter); 107 | if (0 < infoWriter.getCount()) { 108 | return true; 109 | } 110 | } catch (Throwable e) { 111 | e.printStackTrace(); 112 | } finally { 113 | FileUtils.closeQuietly(os); 114 | } 115 | file.delete(); 116 | 117 | Logger.e(TAG, "dump fail: " + items[0]); 118 | return false; 119 | } 120 | 121 | static class DumperWriter implements TstClassPrinter.IClassPrinter { 122 | private int mCount = 0; 123 | private final String mPathName, mClassName; 124 | private final OutputStream mStream; 125 | 126 | public DumperWriter(String pathName, String clsName, OutputStream stream) { 127 | mPathName = pathName; 128 | mClassName = clsName; 129 | mStream = stream; 130 | } 131 | 132 | public int getCount() { return mCount; } 133 | 134 | public void writeHeader() { 135 | try { 136 | mStream.write(("package " + mPathName + ";").getBytes()); 137 | mStream.write("\n\n".getBytes()); 138 | mStream.write(("interface " + mClassName + " {").getBytes()); 139 | } catch (Throwable e) { 140 | e.printStackTrace(); 141 | } 142 | } 143 | 144 | public void writeTailer() throws Throwable { 145 | mStream.write("\n}".getBytes()); 146 | } 147 | 148 | @Override 149 | public void onTstClassPrinter(TstClassPrinter.TRANSACTION_Item item) { 150 | if (mCount <= 0) { 151 | writeHeader(); 152 | } 153 | mCount += 1; 154 | try { 155 | mStream.write(("\n " + item.funcName + ";// " + item.code).getBytes()); 156 | } catch (Throwable e) { 157 | e.printStackTrace(); 158 | } 159 | } 160 | } 161 | 162 | static class DumperInfoWriter implements TstClassPrinter.IClassInfoPrinter { 163 | private int mCount = 0; 164 | private final OutputStream mStream; 165 | 166 | public DumperInfoWriter(OutputStream stream) { 167 | mStream = stream; 168 | } 169 | 170 | public int getCount() { return mCount; } 171 | 172 | @Override 173 | public void onTstClassInfoPrinter(String line) { 174 | mCount += 1; 175 | try { 176 | mStream.write("\n".getBytes()); 177 | mStream.write(line.getBytes()); 178 | } catch (Throwable e) { 179 | e.printStackTrace(); 180 | } 181 | } 182 | } 183 | } 184 | -------------------------------------------------------------------------------- /app/src/main/java/com/ifma/cmpt/demo/module/ClipboadData.java: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.demo.module; 2 | 3 | import android.content.ClipData; 4 | import android.content.ClipboardManager; 5 | import android.content.Context; 6 | import android.text.TextUtils; 7 | 8 | import java.util.ArrayList; 9 | import java.util.HashMap; 10 | import java.util.List; 11 | import java.util.Map; 12 | 13 | public class ClipboadData { 14 | public static final int TYPE_InstantiateClassLoader = 1; 15 | public static final int TYPE_InstantiateApplication = 2; 16 | public static final int TYPE_InstantiateActivity = 3; 17 | public static final int TYPE_Application_attachBaseContext = 4; 18 | public static final int TYPE_Application_onCreate = 5; 19 | public static final int TYPE_Provider_onCreate = 6; 20 | public static final int TYPE_Activity_onCreate = 7; 21 | public static final int TYPE_Thread_Jvm = 8; 22 | public static final int TYPE_Thread_Native = 9; 23 | public static final int TYPE_InstantiateProvider = 10; 24 | public static final int TYPE_Source_APK = 11; 25 | public static final int TYPE_Package_Info = 12; 26 | public static final int TYPE_Usb_Info = 13; 27 | 28 | private static final String PRE = "tst:"; 29 | private static final Map> sCache = new HashMap<>(); 30 | 31 | public static void set(int type, String[] ss) { 32 | if (null == ss) return; 33 | List vv = new ArrayList<>(); 34 | for (String s : ss) vv.add(s); 35 | sCache.put(type, vv); 36 | } 37 | 38 | public static void set(int type, List v) { 39 | sCache.put(type, v); 40 | } 41 | 42 | public static List get(int type) { 43 | return sCache.get(type); 44 | } 45 | 46 | public static void saveToClipboard(Context ctx) { 47 | StringBuilder sb = new StringBuilder(); 48 | sb.append(PRE); 49 | 50 | List ss; 51 | for (Map.Entry> e : sCache.entrySet()) { 52 | ss = e.getValue(); 53 | Integer key = e.getKey(); 54 | for (String s : ss) { 55 | sb.append(key).append('=').append(s).append('\n'); 56 | } 57 | } 58 | writeToClipboard(ctx, sb.toString()); 59 | } 60 | 61 | public static int loadFromClipboard(Context ctx) { 62 | sCache.clear(); 63 | String s = readFromClipboard(ctx); 64 | if (TextUtils.isEmpty(s) || !s.startsWith(PRE)) return 0; 65 | 66 | s = s.substring(PRE.length()); 67 | String[] lines = s.split("\n"); 68 | 69 | int pos; 70 | Integer lastKey = 0; 71 | List ss = new ArrayList<>(); 72 | for (String item : lines) { 73 | pos = item.indexOf('='); 74 | if (pos <= 0) continue; 75 | Integer key = Integer.valueOf(item.substring(0, pos)); 76 | if (key != lastKey) { 77 | if (0 < lastKey && 0 < ss.size()) { 78 | sCache.put(lastKey, ss); 79 | ss = new ArrayList<>(); 80 | } 81 | lastKey = key; 82 | } 83 | ss.add(item.substring(pos+1)); 84 | } 85 | if (0 < lastKey && 0 < ss.size()) { 86 | sCache.put(lastKey, ss); 87 | } 88 | return sCache.size(); 89 | } 90 | 91 | private static void writeToClipboard(Context ctx, String text) { 92 | ClipboardManager clipboard = (ClipboardManager) ctx.getSystemService(Context.CLIPBOARD_SERVICE); 93 | ClipData clip = ClipData.newPlainText("text", text); 94 | clipboard.setPrimaryClip(clip); 95 | } 96 | 97 | private static String readFromClipboard(Context ctx) { 98 | ClipboardManager clipboard = (ClipboardManager) ctx.getSystemService(Context.CLIPBOARD_SERVICE); 99 | ClipData clip = clipboard.getPrimaryClip(); 100 | if (clip != null && clip.getItemCount() > 0) { 101 | ClipData.Item item = clip.getItemAt(0); 102 | return item.getText().toString(); 103 | } 104 | return null; 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /app/src/main/java/com/ifma/cmpt/demo/module/Consts.java: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.demo.module; 2 | 3 | public final class Consts { 4 | public static final String KEY_IN_ARG1 = "key-in-arg1"; 5 | public static final String KEY_IN_ARG2 = "key-in-arg2"; 6 | public static final String KEY_IN_ARG3 = "key-in-arg3"; 7 | public static final String KEY_IN_ARG4 = "key-in-arg4"; 8 | 9 | public static final String KEY_OUT_ARG1 = "key-out-arg1"; 10 | public static final String KEY_OUT_ARG2 = "key-out-arg2"; 11 | public static final String KEY_CODE = "key-code"; 12 | public static final String KEY_MSG = "key-msg"; 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/ifma/cmpt/demo/module/LauncherMonitor.java: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.demo.module; 2 | 3 | import android.content.pm.ActivityInfo; 4 | import android.content.pm.ProviderInfo; 5 | import android.content.pm.ServiceInfo; 6 | import android.os.Handler; 7 | import android.os.Message; 8 | 9 | import com.ifma.cmpt.demo.test.FireyerPackageCase; 10 | import com.ifma.cmpt.demo.test.FireyerRuntimeCase; 11 | import com.ifma.cmpt.fireyer.FireyerManager; 12 | import com.ifma.cmpt.utils.ActivityThreadUtils; 13 | import com.ifma.cmpt.utils.Logger; 14 | import com.ifma.cmpt.utils.ReflectUtils; 15 | 16 | import java.lang.reflect.Method; 17 | import java.util.List; 18 | 19 | public class LauncherMonitor implements Handler.Callback { 20 | private int LAUNCH_ACTIVITY = 0; 21 | private int RELAUNCH_ACTIVITY = 0; 22 | private int CREATE_SERVICE = 0; 23 | private int INSTALL_PROVIDER = 0; 24 | private int EXECUTE_TRANSACTION = 0; 25 | 26 | private static LauncherMonitor sSelf = null; 27 | public static void init() { 28 | if (sSelf == null) { 29 | sSelf = new LauncherMonitor(); 30 | } 31 | sSelf.startMonitor(); 32 | } 33 | 34 | public void startMonitor() { 35 | Object objH = ActivityThreadUtils.getAtH(); 36 | try { 37 | FireyerRuntimeCase.sAT_H_Callback = FireyerManager.checkHCallback(); 38 | 39 | Class cls = objH.getClass(); 40 | Integer val = (Integer)ReflectUtils.getStaticFieldValue(cls, "LAUNCH_ACTIVITY"); 41 | if (null != val) { 42 | this.LAUNCH_ACTIVITY = val; 43 | } 44 | 45 | val = (Integer)ReflectUtils.getStaticFieldValue(cls, "RELAUNCH_ACTIVITY"); 46 | if (null != val) { 47 | this.RELAUNCH_ACTIVITY = val; 48 | } 49 | 50 | val = (Integer)ReflectUtils.getStaticFieldValue(cls, "CREATE_SERVICE"); 51 | if (null != val) { 52 | this.CREATE_SERVICE = val; 53 | } 54 | 55 | val = (Integer)ReflectUtils.getStaticFieldValue(cls, "INSTALL_PROVIDER"); 56 | if (null != val) { 57 | this.INSTALL_PROVIDER = val; 58 | } 59 | 60 | val = (Integer)ReflectUtils.getStaticFieldValue(cls, "EXECUTE_TRANSACTION"); 61 | if (null != val) { 62 | this.EXECUTE_TRANSACTION = val; 63 | } 64 | ReflectUtils.setFieldValue(objH, "mCallback", this); 65 | } catch (Throwable var7) { 66 | Logger.e(var7); 67 | } 68 | } 69 | 70 | @Override 71 | public boolean handleMessage(Message msg) { 72 | try { 73 | if (LAUNCH_ACTIVITY == msg.what || RELAUNCH_ACTIVITY == msg.what) {// ActivityThread$ActivityClientRecord 74 | ActivityInfo ai = (ActivityInfo) ReflectUtils.getFieldValue(msg.obj, "activityInfo"); 75 | FireyerPackageCase.doTestActivityInfo("hcb ", ai, false); 76 | } else if (CREATE_SERVICE == msg.what) {// ActivityThread$CreateServiceData 77 | ServiceInfo info = (ServiceInfo) ReflectUtils.getFieldValue(msg.obj, "info"); 78 | FireyerPackageCase.doTestServiceInfo("hcb ", info, false); 79 | } else if (INSTALL_PROVIDER == msg.what) { 80 | FireyerPackageCase.doTestProviderInfo("hcb ", (ProviderInfo)msg.obj, false); 81 | } else if (EXECUTE_TRANSACTION == msg.what) {// for 9.0 82 | Method m = ReflectUtils.getDeclaredMethod(msg.obj, "getCallbacks"); 83 | List cbs = (List) m.invoke(msg.obj); 84 | if (null != cbs && 0 < cbs.size()) { 85 | Class cls = Class.forName("android.app.servertransaction.LaunchActivityItem"); 86 | for (Object cb : cbs) { 87 | if (cls.isInstance(cb)) { 88 | // android/app/servertransaction/LaunchActivityItem.mInfo (ActivityInfo) 89 | ActivityInfo ai = (ActivityInfo)ReflectUtils.getFieldValue(cb, "mInfo"); 90 | FireyerPackageCase.doTestActivityInfo("hcb ", ai, false); 91 | } 92 | } 93 | } 94 | } 95 | } catch (Throwable e) { 96 | Logger.e(e); 97 | } 98 | return false; 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /app/src/main/java/com/ifma/cmpt/demo/module/PackageDumper.java: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.demo.module; 2 | 3 | import android.content.Context; 4 | import android.content.pm.PackageInfo; 5 | import android.content.pm.PackageManager; 6 | import android.os.Bundle; 7 | 8 | public class PackageDumper { 9 | private static final String TAG = "PackageDumper"; 10 | 11 | public static void handleCallEvent(Context ctx, Bundle inData, Bundle replayData) throws Throwable { 12 | final String pkg = inData.getString(Consts.KEY_IN_ARG1); 13 | PackageManager pm = ctx.getPackageManager(); 14 | PackageInfo pi = pm.getPackageInfo(pkg, 0); 15 | replayData.putString("verName", pi.versionName); 16 | replayData.putLong("verCode", pi.getLongVersionCode()); 17 | replayData.putInt("minSdk", pi.applicationInfo.minSdkVersion); 18 | replayData.putInt("tarSdk", pi.applicationInfo.targetSdkVersion); 19 | replayData.putString("appComp", pi.applicationInfo.appComponentFactory); 20 | CharSequence s = pm.getApplicationLabel(pi.applicationInfo); 21 | replayData.putString("label", s.toString()); 22 | } 23 | 24 | } 25 | -------------------------------------------------------------------------------- /app/src/main/java/com/ifma/cmpt/demo/sub/DocumentReceiverActivity.java: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.demo.sub; 2 | 3 | import android.app.Activity; 4 | import android.content.ContentResolver; 5 | import android.content.Intent; 6 | import android.net.Uri; 7 | import android.os.Bundle; 8 | import android.widget.Toast; 9 | 10 | import java.io.InputStream; 11 | import java.util.ArrayList; 12 | 13 | 14 | public class DocumentReceiverActivity extends Activity { 15 | private static final String TAG = "DocumentReceiverActivity"; 16 | 17 | @Override 18 | protected void onCreate(Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | // setContentView(R.layout.activity_document_receiver); 21 | Intent intent = getIntent(); 22 | String action = intent.getAction(); 23 | String type = intent.getType(); 24 | if (Intent.ACTION_SEND.equals(action) && type != null) { 25 | if (type.startsWith("application/")) { 26 | handleSendDocument(intent); 27 | } 28 | } else if (Intent.ACTION_SEND_MULTIPLE.equals(action) && type != null) { 29 | if (type.startsWith("application/")) { 30 | handleSendMultipleDocuments(intent); 31 | } 32 | } 33 | } 34 | 35 | void handleSendDocument(Intent intent) { 36 | Uri documentUri = intent.getParcelableExtra(Intent.EXTRA_STREAM); 37 | if (documentUri != null) { 38 | int len = readFileContent(documentUri); 39 | if (0 < len) { 40 | Toast.makeText(getApplicationContext(), "Got file size: " + len, Toast.LENGTH_SHORT).show(); 41 | return; 42 | } 43 | } 44 | Toast.makeText(getApplicationContext(), "Receive file fail", Toast.LENGTH_SHORT).show(); 45 | } 46 | 47 | void handleSendMultipleDocuments(Intent intent) { 48 | ArrayList documentUris = intent.getParcelableArrayListExtra(Intent.EXTRA_STREAM); 49 | if (documentUris != null) { 50 | StringBuilder sb = new StringBuilder(); 51 | sb.append("Got ").append(documentUris.size()).append(" files"); 52 | for (Uri documentUri : documentUris) { 53 | int len = readFileContent(documentUri); 54 | sb.append(", ").append(len); 55 | } 56 | Toast.makeText(getApplicationContext(), sb.toString(), Toast.LENGTH_LONG).show(); 57 | } else { 58 | Toast.makeText(getApplicationContext(), "Receive file fail", Toast.LENGTH_LONG).show(); 59 | } 60 | } 61 | 62 | int readFileContent(Uri documentUri) { 63 | ContentResolver contentResolver = getContentResolver(); 64 | try (InputStream inputStream = contentResolver.openInputStream(documentUri)) { 65 | if (inputStream != null) { 66 | byte[] buffer = new byte[4096]; 67 | 68 | int fileSize = 0; 69 | int len; 70 | while((len = inputStream.read(buffer, 0, 4096)) != -1) { 71 | if (len > 0) { 72 | fileSize += len; 73 | } 74 | } 75 | return fileSize; 76 | } 77 | } catch (Throwable e) { 78 | e.printStackTrace(); 79 | // 处理读取文件时的其他I/O错误 80 | } 81 | return -1; 82 | } 83 | 84 | } 85 | -------------------------------------------------------------------------------- /app/src/main/java/com/ifma/cmpt/demo/sub/SingleProvider.java: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.demo.sub; 2 | 3 | import android.content.ContentProvider; 4 | import android.content.ContentValues; 5 | import android.database.Cursor; 6 | import android.net.Uri; 7 | import android.os.Bundle; 8 | 9 | import com.ifma.cmpt.demo.fireyer.R; 10 | import com.ifma.cmpt.testin.env.TstLogger; 11 | 12 | 13 | public class SingleProvider extends ContentProvider { 14 | private static final String TAG = SingleProvider.class.getSimpleName(); 15 | 16 | @Override 17 | public boolean onCreate() { 18 | TstLogger.e(TAG, "onCreate"); 19 | return false; 20 | } 21 | 22 | @Override 23 | public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { 24 | TstLogger.e(TAG, "query"); 25 | return null; 26 | } 27 | 28 | @Override 29 | public String getType(Uri uri) { 30 | TstLogger.e(TAG, "getType"); 31 | return getContext().getResources().getString(R.string.test_single_string); 32 | } 33 | 34 | @Override 35 | public Uri insert(Uri uri, ContentValues values) { 36 | TstLogger.e(TAG, "insert"); 37 | return null; 38 | } 39 | 40 | @Override 41 | public int delete(Uri uri, String selection, String[] selectionArgs) { 42 | TstLogger.e(TAG, "delete"); 43 | return 0; 44 | } 45 | 46 | @Override 47 | public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 48 | TstLogger.e(TAG, "update"); 49 | return 0; 50 | } 51 | 52 | public Bundle call(String authority, String method, String arg, Bundle extras) { 53 | return null; 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /app/src/main/java/com/ifma/cmpt/demo/sub/SubActivity.java: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.demo.sub; 2 | 3 | import android.app.Activity; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | import android.view.View; 7 | import android.widget.TextView; 8 | 9 | import com.ifma.cmpt.demo.fireyer.BuildConfig; 10 | import com.ifma.cmpt.demo.fireyer.R; 11 | import com.ifma.cmpt.demo.main.ConsoleActivity; 12 | import com.ifma.cmpt.testin.env.TstConsts; 13 | import com.ifma.cmpt.testin.env.TstHandler; 14 | import com.ifma.cmpt.testin.env.TstLogger; 15 | import com.ifma.cmpt.testin.module.TstPermissionGrantor; 16 | //import com.ifma.cmpt.fireyer.FireyerNative; 17 | 18 | 19 | public class SubActivity extends Activity implements View.OnClickListener { 20 | private static final String TAG = "MainActivity"; 21 | 22 | @Override 23 | public void onCreate(Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | setContentView(R.layout.activity_main); 26 | initView(); 27 | TstPermissionGrantor.grant(this); 28 | initData(); 29 | } 30 | 31 | private void initView() { 32 | TextView text = (TextView) findViewById(R.id.main_version); 33 | text.setText("v" + BuildConfig.VERSION_NAME + "(" + BuildConfig.VERSION_CODE + ")"); 34 | View v; 35 | v = findViewById(R.id.item_unittest); 36 | // v.setVisibility(View.GONE); 37 | v.setOnClickListener(this); 38 | 39 | v = findViewById(R.id.item_xxx); 40 | // v.setVisibility(View.GONE); 41 | v.setOnClickListener(this); 42 | } 43 | 44 | public void onClick(View v) { 45 | switch (v.getId()) { 46 | case R.id.item_unittest: 47 | { 48 | Intent i = new Intent(this, ConsoleActivity.class); 49 | i.putExtra(TstConsts.KEY_FROM, "MainActivity"); 50 | i.putExtra(TstConsts.KEY_TYPE, TstConsts.VALUE_UNITTEST); 51 | startActivity(i); 52 | } break; 53 | case R.id.item_xxx: 54 | break; 55 | default: break; 56 | } 57 | } 58 | 59 | private void initData() { 60 | final Bundle args = getIntent().getExtras(); 61 | TstLogger.bundle(TAG, args); 62 | if (null == args) return; 63 | 64 | TstHandler.post(new Runnable() { 65 | @Override 66 | public void run() { 67 | final int type = args.getInt(TstConsts.KEY_TYPE); 68 | switch (type) { 69 | case TstConsts.TYPE_CALL_UNIT_TEST: 70 | // FireyerNative.unitTest(); 71 | break; 72 | default: break; 73 | } 74 | } 75 | }); 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /app/src/main/java/com/ifma/cmpt/demo/sub/SubPermissionProvider.java: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.demo.sub; 2 | 3 | import android.content.ContentProvider; 4 | import android.content.ContentValues; 5 | import android.database.Cursor; 6 | import android.net.Uri; 7 | import android.os.Bundle; 8 | import android.text.TextUtils; 9 | 10 | import com.ifma.cmpt.testin.env.TstLogger; 11 | 12 | 13 | public class SubPermissionProvider extends ContentProvider { 14 | private static final String TAG = SubPermissionProvider.class.getSimpleName(); 15 | 16 | @Override 17 | public boolean onCreate() { 18 | TstLogger.e(TAG, "onCreate"); 19 | return false; 20 | } 21 | 22 | @Override 23 | public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { 24 | TstLogger.e(TAG, "query"); 25 | return null; 26 | } 27 | 28 | @Override 29 | public String getType(Uri uri) { 30 | TstLogger.e(TAG, "getType"); 31 | return "SubProvider"; 32 | } 33 | 34 | @Override 35 | public Uri insert(Uri uri, ContentValues values) { 36 | TstLogger.e(TAG, "insert"); 37 | return null; 38 | } 39 | 40 | @Override 41 | public int delete(Uri uri, String selection, String[] selectionArgs) { 42 | TstLogger.e(TAG, "delete"); 43 | return 0; 44 | } 45 | 46 | @Override 47 | public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 48 | TstLogger.e(TAG, "update"); 49 | return 0; 50 | } 51 | 52 | public Bundle call(String authority, String method, String arg, Bundle extras) { 53 | TstLogger.e(TAG, "call"); 54 | TstLogger.bundle(TAG, extras); 55 | boolean succ = false; 56 | do { 57 | if (!TextUtils.equals(authority, "com.ifma.cmpt.demo.fireyer.SubProvider")) break; 58 | if (!TextUtils.equals(method, "method")) break; 59 | if (!TextUtils.equals(arg, "arg")) break; 60 | if (1 != extras.size()) break; 61 | if (100 != extras.getInt("call")) break; 62 | succ = true; 63 | } while (false); 64 | 65 | Bundle replyData = new Bundle(); 66 | replyData.putBoolean("call", succ); 67 | return replyData; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/ifma/cmpt/demo/sub/SubProvider.java: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.demo.sub; 2 | 3 | import android.content.ContentProvider; 4 | import android.content.ContentValues; 5 | import android.database.Cursor; 6 | import android.net.Uri; 7 | import android.os.Bundle; 8 | import android.text.TextUtils; 9 | 10 | import com.ifma.cmpt.testin.env.TstLogger; 11 | 12 | 13 | public class SubProvider extends ContentProvider { 14 | private static final String TAG = SubProvider.class.getSimpleName(); 15 | 16 | @Override 17 | public boolean onCreate() { 18 | TstLogger.e(TAG, "onCreate"); 19 | return false; 20 | } 21 | 22 | @Override 23 | public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) { 24 | TstLogger.e(TAG, "query"); 25 | return null; 26 | } 27 | 28 | @Override 29 | public String getType(Uri uri) { 30 | TstLogger.e(TAG, "getType"); 31 | return "SubProvider"; 32 | } 33 | 34 | @Override 35 | public Uri insert(Uri uri, ContentValues values) { 36 | TstLogger.e(TAG, "insert"); 37 | return null; 38 | } 39 | 40 | @Override 41 | public int delete(Uri uri, String selection, String[] selectionArgs) { 42 | TstLogger.e(TAG, "delete"); 43 | return 0; 44 | } 45 | 46 | @Override 47 | public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) { 48 | TstLogger.e(TAG, "update"); 49 | return 0; 50 | } 51 | 52 | public Bundle call(String authority, String method, String arg, Bundle extras) { 53 | TstLogger.e(TAG, "call"); 54 | TstLogger.bundle(TAG, extras); 55 | boolean succ = false; 56 | do { 57 | if (!TextUtils.equals(authority, "com.ifma.cmpt.demo.fireyer.SubProvider")) break; 58 | if (!TextUtils.equals(method, "method")) break; 59 | if (!TextUtils.equals(arg, "arg")) break; 60 | if (1 != extras.size()) break; 61 | if (100 != extras.getInt("call")) break; 62 | succ = true; 63 | } while (false); 64 | 65 | Bundle replyData = new Bundle(); 66 | replyData.putBoolean("call", succ); 67 | return replyData; 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /app/src/main/java/com/ifma/cmpt/demo/sub/SubReceiver.java: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.demo.sub; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.content.IntentFilter; 7 | 8 | import com.ifma.cmpt.testin.env.TstConsts; 9 | import com.ifma.cmpt.testin.env.TstLogger; 10 | 11 | 12 | public class SubReceiver extends BroadcastReceiver { 13 | private static final String TAG = SubReceiver.class.getSimpleName(); 14 | 15 | public static void register(Context ctx) { 16 | ctx.registerReceiver(new SubReceiver(), new IntentFilter(TstConsts.getActionReceiver())); 17 | } 18 | 19 | @Override 20 | public void onReceive(Context context, Intent intent) { 21 | TstLogger.bundle(TAG, intent.getExtras()); 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /app/src/main/java/com/ifma/cmpt/demo/sub/SubService.java: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.demo.sub; 2 | 3 | import android.app.Service; 4 | import android.content.Intent; 5 | import android.media.CreateRecordRequest; 6 | import android.media.CreateRecordResponse; 7 | import android.os.Bundle; 8 | import android.os.IBinder; 9 | import android.os.Message; 10 | import android.os.RemoteException; 11 | import android.text.TextUtils; 12 | 13 | import com.ifma.cmpt.demo.IBinderTest; 14 | import com.ifma.cmpt.demo.IBinderTestCallback; 15 | import com.ifma.cmpt.demo.test.FireyerCaseConsts; 16 | import com.ifma.cmpt.testin.env.TstHandler; 17 | import com.ifma.cmpt.testin.env.TstLogger; 18 | import com.ifma.cmpt.utils.Logger; 19 | import com.ifma.cmpt.utils.MessengerUtils; 20 | 21 | public class SubService extends Service implements MessengerUtils.IServiceCallback { 22 | private static final String TAG = SubService.class.getSimpleName(); 23 | 24 | public static final String ACTION_BINDER = "key-binder"; 25 | public static final String ACTION_MESSAGE = "key-message"; 26 | 27 | MessengerUtils.ServiceMessenger mMessenger; 28 | public void onCreate() { 29 | super.onCreate(); 30 | mMessenger = new MessengerUtils.ServiceMessenger(this, TstHandler.getLooper()); 31 | } 32 | 33 | @Override 34 | public Message handleMessage(Message msg) { 35 | if (Logger.D) Logger.d(TAG, "handleMessage: " + msg.toString()); 36 | 37 | final Bundle inData = msg.getData(); 38 | final Bundle replyData = new Bundle(); 39 | do { 40 | if (msg.what != inData.getInt("msg")) break; 41 | if (1 != inData.size()) break; 42 | replyData.putInt("call", msg.what); 43 | } while (false); 44 | 45 | Message outMessage = Message.obtain(null, msg.what); 46 | outMessage.setData(replyData); 47 | return outMessage; 48 | } 49 | 50 | @Override 51 | public IBinder onBind(Intent intent) { 52 | if (TextUtils.equals(ACTION_BINDER, intent.getAction())) { 53 | FireyerCaseConsts.setMode(intent.getIntExtra(FireyerCaseConsts.KEY_MODE, FireyerCaseConsts.MODE_SOURCE)); 54 | return mBinderTest; 55 | } 56 | if (TextUtils.equals(ACTION_MESSAGE, intent.getAction())) { 57 | return mMessenger.getBinder(); 58 | } 59 | return null; 60 | } 61 | 62 | @Override 63 | public void onDestroy() { 64 | super.onDestroy(); 65 | } 66 | 67 | @Override 68 | public int onStartCommand(Intent intent, int flags, int startId) { 69 | TstLogger.d(TAG, intent.toString()); 70 | return START_NOT_STICKY; 71 | } 72 | 73 | private static String getPre() { 74 | return FireyerCaseConsts.isSourceMode() ? "" : FireyerCaseConsts.KEY_PRE; 75 | } 76 | 77 | private final IBinderTest.Stub mBinderTest = new IBinderTest.Stub() { 78 | 79 | @Override 80 | public int callBinderTest1(String a, IBinder c, int d) throws RemoteException { 81 | Logger.d(TAG, "callBinderTest1 >>>"); 82 | Logger.d(TAG, "callBinderTest1 a: " + a + " -> " + getPre() + FireyerCaseConsts.KEY_BINDER_ARG_A); 83 | Logger.d(TAG, "callBinderTest1 d: " + d); 84 | Logger.d(TAG, "callBinderTest binder c: " + c); 85 | if (!TextUtils.equals(a, getPre() + FireyerCaseConsts.KEY_BINDER_ARG_A)) return -1; 86 | if (d != 100) return -5; 87 | if (null == c) return -6; 88 | IBinderTestCallback cb = IBinderTestCallback.Stub.asInterface(c); 89 | if (2 != cb.handleBinderTestCallback(1)) return -8; 90 | 91 | return 0; 92 | } 93 | 94 | @Override 95 | public int callBinderTest2(int a, IBinder b, String c) throws RemoteException { 96 | Logger.d(TAG, "callBinderTest2 >>>"); 97 | Logger.d(TAG, "callBinderTest2 a: " + a); 98 | Logger.d(TAG, "callBinderTest2 c: " + c); 99 | Logger.d(TAG, "callBinderTest binder b: " + b); 100 | if (!TextUtils.equals(c, getPre() + FireyerCaseConsts.KEY_BINDER_ARG_C)) return -1; 101 | if (a != 100) return -5; 102 | if (null == b) return -6; 103 | IBinderTestCallback cb = IBinderTestCallback.Stub.asInterface(b); 104 | if (2 != cb.handleBinderTestCallback(1)) return -8; 105 | 106 | return 0; 107 | } 108 | 109 | public int callBinderTest(String a, String b, IBinder c, int d, String e, IBinder f, String g) throws RemoteException { 110 | Logger.d(TAG, "callBinderTest >>>"); 111 | Logger.d(TAG, "callBinderTest a: " + a); 112 | Logger.d(TAG, "callBinderTest b: " + b); 113 | Logger.d(TAG, "callBinderTest e: " + e); 114 | Logger.d(TAG, "callBinderTest g: " + g); 115 | Logger.d(TAG, "callBinderTest binder c: " + c); 116 | Logger.d(TAG, "callBinderTest binder f: " + f); 117 | if (!TextUtils.equals(a, getPre() + FireyerCaseConsts.KEY_BINDER_ARG_A)) return -1; 118 | if (!TextUtils.equals(b, getPre() + FireyerCaseConsts.KEY_BINDER_ARG_B)) return -2; 119 | if (!TextUtils.equals(e, getPre() + FireyerCaseConsts.KEY_BINDER_ARG_C)) return -3; 120 | if (!TextUtils.equals(g, getPre() + FireyerCaseConsts.KEY_BINDER_ARG_D)) return -4; 121 | if (d != 100) return -5; 122 | if (null == c) return -6; 123 | if (null == f) return -7; 124 | IBinderTestCallback cb = IBinderTestCallback.Stub.asInterface(c); 125 | if (2 != cb.handleBinderTestCallback(1)) return -8; 126 | 127 | cb = IBinderTestCallback.Stub.asInterface(f); 128 | if (3 != cb.handleBinderTestCallback(2)) return -9; 129 | 130 | return 0; 131 | } 132 | 133 | @Override 134 | public CreateRecordResponse createRecord(CreateRecordRequest request) throws RemoteException { 135 | Logger.d("xxx", "pkg: " + request.clientInfo.attributionSource.packageName); 136 | return null; 137 | } 138 | 139 | }; 140 | } 141 | -------------------------------------------------------------------------------- /app/src/main/java/com/ifma/cmpt/demo/test/FireyerAccessibilityCase.java: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.demo.test; 2 | 3 | import android.accessibilityservice.AccessibilityServiceInfo; 4 | import android.content.Context; 5 | import android.provider.Settings; 6 | import android.text.TextUtils; 7 | import android.view.accessibility.AccessibilityManager; 8 | 9 | import com.ifma.cmpt.testin.module.TstCaseBase; 10 | import com.ifma.cmpt.testin.module.TstRunner; 11 | 12 | import java.util.Arrays; 13 | import java.util.HashSet; 14 | import java.util.List; 15 | import java.util.Locale; 16 | 17 | /** 18 | * 辅助功能 19 | */ 20 | public class FireyerAccessibilityCase extends TstCaseBase { 21 | 22 | // private static final String TARGET_ACCESSIBILITY_SERVICE_ID = "com.mac.accessbility_demo/com.mac.accessibility_demo.AccessibilitySampleService"; 23 | private static final HashSet sHidden_Service_Pkgs = new HashSet<>(Arrays.asList("android.app.se.apop","com.isyner.client")); 24 | 25 | public void testServicesList(){ 26 | Context context = getContext(); 27 | AccessibilityManager am = (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE); 28 | String svcList = getEnabledAccessibilityServices(context); 29 | boolean filterFailed = false; 30 | if (!TextUtils.isEmpty(svcList)){ 31 | for (String pkg:sHidden_Service_Pkgs){ 32 | if (svcList.contains(pkg + "/") || svcList.contains(":" + pkg + "/")){ 33 | filterFailed = true; 34 | break; 35 | } 36 | } 37 | } 38 | TstRunner.print("svc list:" + svcList,!filterFailed); 39 | boolean isEnabled = am.isEnabled(); 40 | boolean isTouchExplorationEnabled = am.isTouchExplorationEnabled(); 41 | TstRunner.print("check isEnabled:"+isEnabled+", isTouchExplorationEnabled:"+isTouchExplorationEnabled,((isEnabled || isTouchExplorationEnabled) && !TextUtils.isEmpty(svcList)) 42 | || (!isEnabled && !isTouchExplorationEnabled && TextUtils.isEmpty(svcList))); 43 | 44 | } 45 | 46 | public void testSpecEnable(){ 47 | Context context = getContext(); 48 | boolean isSpecEnable = isSpecificAccessibilityServiceEnabled(context); 49 | TstRunner.print("isSpecEnable check",!isSpecEnable); 50 | } 51 | 52 | 53 | 54 | /** 55 | * 获取所有已启用的辅助服务 56 | * 57 | * @param context 上下文 58 | * @return 已启用的辅助服务列表字符串 59 | */ 60 | public static String getEnabledAccessibilityServices(Context context) { 61 | return Settings.Secure.getString(context.getContentResolver(), 62 | Settings.Secure.ENABLED_ACCESSIBILITY_SERVICES); 63 | } 64 | 65 | public static boolean isSpecificAccessibilityServiceEnabled(Context context) { 66 | AccessibilityManager am = (AccessibilityManager) context.getSystemService(Context.ACCESSIBILITY_SERVICE); 67 | if (am == null || !am.isEnabled()) { 68 | return false; 69 | } 70 | List enabledServices = am.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK); 71 | 72 | for (AccessibilityServiceInfo service : enabledServices) { 73 | String pkg = service.getId().split("/")[0]; 74 | if (sHidden_Service_Pkgs.contains(pkg)){ 75 | return true; 76 | } 77 | } 78 | return false; 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /app/src/main/java/com/ifma/cmpt/demo/test/FireyerCaseConsts.java: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.demo.test; 2 | 3 | public final class FireyerCaseConsts { 4 | public static final String PACKAGE_NAME = "com.ifma.cmpt.demo.fireyer"; 5 | 6 | public static final int MODE_SOURCE = 1;// origin install env 7 | public static final int MODE_KONKER = 2;// konker env 8 | public static final int MODE_PACKER = 3;// pack env 9 | 10 | public static final String KEY_MODE = "key-mode"; 11 | 12 | private static int sMode = MODE_SOURCE; 13 | public static void setMode(int mode) { sMode = mode; } 14 | public static int getMode() { return sMode; } 15 | public static boolean isSourceMode() { return sMode == MODE_SOURCE; } 16 | public static boolean isKonkerMode() { return sMode == MODE_KONKER; } 17 | public static boolean isPackerMode() { return sMode == MODE_PACKER; } 18 | 19 | public static boolean isVirtualMode() { return sMode == MODE_KONKER || sMode == MODE_PACKER; } 20 | 21 | public static final String KEY_BINDER_ARG_A = PACKAGE_NAME; 22 | public static final String KEY_BINDER_ARG_B = PACKAGE_NAME; 23 | public static final String KEY_BINDER_ARG_C = PACKAGE_NAME; 24 | public static final String KEY_BINDER_ARG_D = PACKAGE_NAME; 25 | 26 | public static final String KEY_PRE = "mts.konker.l2."; 27 | } 28 | -------------------------------------------------------------------------------- /app/src/main/java/com/ifma/cmpt/demo/test/FireyerDeviceModelCase.java: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.demo.test; 2 | 3 | import android.os.Build; 4 | 5 | import com.ifma.cmpt.fireyer.FireyerManager; 6 | import com.ifma.cmpt.fireyer.FireyerUtils; 7 | import com.ifma.cmpt.testin.module.TstCaseBase; 8 | import com.ifma.cmpt.testin.module.TstRunner; 9 | 10 | import java.io.BufferedReader; 11 | import java.io.InputStreamReader; 12 | 13 | /** 14 | * 设备机型、版本号 15 | */ 16 | public class FireyerDeviceModelCase extends TstCaseBase { 17 | 18 | /** 19 | * Build.BOARD k6833v1_64_k510 20 | * Build.ID TP1A.220624.014 21 | * Build.DISPLAY TP1A.220624.014 release-keys 22 | * Build.PRODUCT PD2318M1 23 | * Build.DEVICE PD2318 24 | * Build.MODEL V2318A 25 | */ 26 | 27 | public void testGetDeviceInfo() { 28 | String fakeFingerPrint = "fake_fingerprint"; 29 | String realFP = ""; 30 | TstRunner.print("Build.FINGERPRINT:" + Build.FINGERPRINT, fakeFingerPrint.equals(Build.FINGERPRINT)); 31 | //popen("getprop","r") 32 | realFP = FireyerManager.getPropByPopen("ro.build.fingerprint"); 33 | TstRunner.print("getPropByPopen:" + realFP,fakeFingerPrint.equals(realFP)); 34 | //__system_property_get 35 | realFP = FireyerManager.getPropBySPG("ro.build.fingerprint"); 36 | TstRunner.print("getPropBySPG:" + realFP,fakeFingerPrint.equals(realFP)); 37 | //__system_property_read_callback 38 | realFP = FireyerManager.getPropBySPRC("ro.build.fingerprint"); 39 | TstRunner.print("getPropBySPRC:" + realFP,fakeFingerPrint.equals(realFP)); 40 | //W/System.err: java.io.IOException: Cannot run program "getprop": error=-1409064192, Exec failed 41 | getFromRuntime(); 42 | } 43 | 44 | private static void getFromRuntime(){ 45 | Process process = null; 46 | BufferedReader reader = null; 47 | try { 48 | process = Runtime.getRuntime().exec("getprop ro.build.fingerprint"); 49 | reader = new BufferedReader(new InputStreamReader(process.getInputStream())); 50 | StringBuilder builder = new StringBuilder(); 51 | String tmp; 52 | while ((tmp = reader.readLine()) != null){ 53 | builder.append(tmp); 54 | builder.append("\n"); 55 | } 56 | TstRunner.print("runtime fingerprint:"+builder.toString()); 57 | } catch (Exception e) { 58 | e.printStackTrace(); 59 | }finally { 60 | FireyerUtils.closeQuietly(reader); 61 | if (process != null){ 62 | process.destroy(); 63 | } 64 | } 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /app/src/main/java/com/ifma/cmpt/demo/test/FireyerDevicePolicyManagerCase.java: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.demo.test; 2 | 3 | import android.app.admin.DevicePolicyManager; 4 | import android.content.ComponentName; 5 | import android.content.Context; 6 | 7 | import com.ifma.cmpt.testin.module.TstCaseBase; 8 | import com.ifma.cmpt.testin.module.TstRunner; 9 | 10 | import java.util.List; 11 | 12 | /** 13 | * 设备管理器 14 | */ 15 | public class FireyerDevicePolicyManagerCase extends TstCaseBase { 16 | 17 | private static final String TARGET_COMPONENTNAME_PKG = "com.uusafe.frame.nut"; 18 | private static final String TARGET_COMPONENTNAME_CLS = "com.uusafe.root.policy.DeviceOwnerReceiver"; 19 | 20 | public void testDeviceAdmin(){ 21 | Context context = getContext(); 22 | TstRunner.print("DeviceAdmin not found target" , isDeviceAdminFound(context)); 23 | TstRunner.print("deviceAdminEnabled false" , !isDeviceAdminEnabled(context, new ComponentName(TARGET_COMPONENTNAME_PKG, TARGET_COMPONENTNAME_CLS))); 24 | } 25 | 26 | public void testProfile(){ 27 | Context context = getContext(); 28 | DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); 29 | TstRunner.print("isProfileOwnerApp check",!dpm.isProfileOwnerApp(TARGET_COMPONENTNAME_PKG)); 30 | } 31 | 32 | /** 33 | * 检查是否有任何设备管理服务被启用 34 | * 35 | * @param context 上下文 36 | * @return 设备管理服务是否被启用 37 | */ 38 | public static boolean isDeviceAdminFound(Context context) { 39 | DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); 40 | List activeAdmins = dpm.getActiveAdmins(); 41 | if (activeAdmins == null) return true; 42 | for (ComponentName cn:activeAdmins){ 43 | if (TARGET_COMPONENTNAME_PKG.equals(cn.getPackageName()) && 44 | TARGET_COMPONENTNAME_CLS.equals(cn.getClassName())){ 45 | return false; 46 | } 47 | } 48 | return true; 49 | } 50 | 51 | /** 52 | * 检查特定的设备管理服务是否启用 53 | * 54 | * @param context 上下文 55 | * @param adminComponent 设备管理服务的组件名称 56 | * @return 该设备管理服务是否启用 57 | */ 58 | public static boolean isDeviceAdminEnabled(Context context, ComponentName adminComponent) { 59 | DevicePolicyManager dpm = (DevicePolicyManager) context.getSystemService(Context.DEVICE_POLICY_SERVICE); 60 | return dpm.isAdminActive(adminComponent); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/com/ifma/cmpt/demo/test/FireyerStackCase.java: -------------------------------------------------------------------------------- 1 | /** 2 | * @brief: test case 3 | * only the method which is public and start with "test" will be run, such as: 4 | * public void testXXX() { 5 | * // TODO something ... 6 | * } 7 | * */ 8 | package com.ifma.cmpt.demo.test; 9 | 10 | import android.os.Build; 11 | import android.text.TextUtils; 12 | 13 | import com.ifma.cmpt.demo.module.ClipboadData; 14 | import com.ifma.cmpt.testin.module.TstCaseBase; 15 | import com.ifma.cmpt.testin.module.TstRunner; 16 | import com.ifma.cmpt.utils.OSUtils; 17 | 18 | import java.util.ArrayList; 19 | import java.util.List; 20 | 21 | public class FireyerStackCase extends TstCaseBase { 22 | private static final String TAG = "FireyerStackCase"; 23 | 24 | protected void setUp() throws Exception { 25 | super.setUp(); 26 | } 27 | 28 | protected void tearDown() throws Exception { 29 | super.tearDown(); 30 | } 31 | 32 | private static void dumpThreadStack(int type, List stacks) { 33 | try { 34 | StackTraceElement[] ee = new Exception("Stack trace").getStackTrace(); 35 | for (StackTraceElement e : ee) { 36 | stacks.add(e.getClassName() + "." + e.getMethodName()); 37 | } 38 | } catch (Throwable e) { 39 | e.printStackTrace(); 40 | } 41 | ClipboadData.set(type, stacks); 42 | } 43 | 44 | private static List sActivity_onCreate = new ArrayList<>(); 45 | public static void dumpStackForActivity_onCreate() { 46 | dumpThreadStack(ClipboadData.TYPE_Activity_onCreate, sActivity_onCreate); 47 | } 48 | 49 | private static List sInstantiateClassLoader = new ArrayList<>(); 50 | public static void dumpStackForInstantiateClassLoader() { 51 | dumpThreadStack(ClipboadData.TYPE_InstantiateClassLoader, sInstantiateClassLoader); 52 | } 53 | 54 | private static List sInstantiateApplication = new ArrayList<>(); 55 | public static void dumpStackForInstantiateApplication() { 56 | dumpThreadStack(ClipboadData.TYPE_InstantiateApplication, sInstantiateApplication); 57 | } 58 | 59 | private static List sInstantiateActivity = new ArrayList<>(); 60 | public static void dumpStackForInstantiateActivity() { 61 | dumpThreadStack(ClipboadData.TYPE_InstantiateActivity, sInstantiateActivity); 62 | } 63 | 64 | private static List sApplication_attachBaseContext = new ArrayList<>(); 65 | public static void dumpStackForApplication_attachBaseContext() { 66 | dumpThreadStack(ClipboadData.TYPE_Application_attachBaseContext, sApplication_attachBaseContext); 67 | } 68 | 69 | private static List sApplication_onCreate = new ArrayList<>(); 70 | public static void dumpStackForApplication_onCreate() { 71 | dumpThreadStack(ClipboadData.TYPE_Application_onCreate, sApplication_onCreate); 72 | } 73 | 74 | private static List sInstantiateProvider = new ArrayList<>(); 75 | public static void dumpStackForInstantiateProvider () { 76 | dumpThreadStack(ClipboadData.TYPE_InstantiateProvider , sInstantiateProvider); 77 | } 78 | 79 | private static List sProvider_onCreate = new ArrayList<>(); 80 | public static void dumpStackForProvider_onCreate () { 81 | dumpThreadStack(ClipboadData.TYPE_Provider_onCreate , sProvider_onCreate); 82 | } 83 | 84 | private static void compareStacks(String tag, List currStacks, List cacheStacks) { 85 | boolean succ = true; 86 | int i = 0; 87 | while (i < currStacks.size() && i < cacheStacks.size()) { 88 | if (!TextUtils.equals(currStacks.get(i), cacheStacks.get(i))) { 89 | succ = false; 90 | TstRunner.print(tag + " unknown stack: " + currStacks.get(i), false); 91 | } 92 | ++ i; 93 | } 94 | if (cacheStacks.size() < currStacks.size()) { 95 | while (i < currStacks.size()) { 96 | succ = false; 97 | TstRunner.print(tag + " unknown stack: " + currStacks.get(i), false); 98 | ++ i; 99 | } 100 | } else if (currStacks.size() < cacheStacks.size()) { 101 | while (i < cacheStacks.size()) { 102 | succ = false; 103 | TstRunner.print(tag + " miss stack: " + cacheStacks.get(i), false); 104 | ++ i; 105 | } 106 | } 107 | 108 | if (succ) { 109 | TstRunner.print(tag + " stack", true); 110 | } 111 | } 112 | 113 | private static void doTestStack(String tag, int type, List currStacks) { 114 | List cacheStacks = ClipboadData.get(type); 115 | if (null == cacheStacks) { 116 | TstRunner.print(tag + " stack: " + currStacks.size() + " == null(origin)", false); 117 | } else { 118 | compareStacks(tag, currStacks, cacheStacks); 119 | } 120 | } 121 | 122 | public static void testStack() { 123 | if (OSUtils.ENV_SDK_INT_P_28_9 < Build.VERSION.SDK_INT) { 124 | doTestStack("InstantiateClassLoader", ClipboadData.TYPE_InstantiateClassLoader, sInstantiateClassLoader); 125 | } 126 | doTestStack("InstantiateApplication", ClipboadData.TYPE_InstantiateApplication, sInstantiateApplication); 127 | doTestStack("InstantiateActivity", ClipboadData.TYPE_InstantiateActivity, sInstantiateActivity); 128 | doTestStack("InstantiateProvider", ClipboadData.TYPE_InstantiateProvider, sInstantiateProvider); 129 | doTestStack("attachBaseContext", ClipboadData.TYPE_Application_attachBaseContext, sApplication_attachBaseContext); 130 | doTestStack("Application_onCreate", ClipboadData.TYPE_Application_onCreate, sApplication_onCreate); 131 | doTestStack("Provider_onCreate", ClipboadData.TYPE_Provider_onCreate, sProvider_onCreate); 132 | doTestStack("Activity_onCreate", ClipboadData.TYPE_Activity_onCreate, sActivity_onCreate); 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/activity.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iofomo/fireyer/05b26b41c381a198ddfd7a6f9fa2d6ec694be9f1/app/src/main/res/drawable-hdpi/activity.png -------------------------------------------------------------------------------- /app/src/main/res/drawable-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iofomo/fireyer/05b26b41c381a198ddfd7a6f9fa2d6ec694be9f1/app/src/main/res/drawable-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/drawable/list_item_bg_single_selected.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/list_item_bg_single_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/list_item_bg_single_unselected.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/welcome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iofomo/fireyer/05b26b41c381a198ddfd7a6f9fa2d6ec694be9f1/app/src/main/res/drawable/welcome.png -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_console.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 15 | 21 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 17 | 18 | 23 | 24 | 25 | 33 | 34 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_sub.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 17 | 18 | 23 | 24 | 25 | 33 | 34 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_test.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 17 | 18 | 23 | 24 | 25 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_input.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iofomo/fireyer/05b26b41c381a198ddfd7a6f9fa2d6ec694be9f1/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iofomo/fireyer/05b26b41c381a198ddfd7a6f9fa2d6ec694be9f1/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iofomo/fireyer/05b26b41c381a198ddfd7a6f9fa2d6ec694be9f1/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iofomo/fireyer/05b26b41c381a198ddfd7a6f9fa2d6ec694be9f1/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iofomo/fireyer/05b26b41c381a198ddfd7a6f9fa2d6ec694be9f1/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/raw/testraw.txt: -------------------------------------------------------------------------------- 1 | got-this -------------------------------------------------------------------------------- /app/src/main/res/values/booleans.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | true 4 | false 5 | true 6 | false 7 | 8 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #ffffffff 4 | #77000000 5 | #66000000 6 | #66000000 7 | #ff000000 8 | #99000000 9 | #66ffffff 10 | #ffffffff 11 | #ffff0000 12 | #ffcccccc 13 | #ffc4c4c4 14 | 15 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/integers.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1 4 | 2 5 | 6 | 10 7 | 20 8 | 9 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Fireyer 3 | 4 | 确定 5 | 取消 6 | 7 | 8 | 下一步 9 | 分享 10 | 提示 11 | 已启用 12 | 未启用 13 | 提交 14 | 重置 15 | 16 | 控制台 17 | 18 | 单元测试【原包使用】 19 | 单元测试【分身使用】 20 | XXX 21 | 文件分享 22 | 23 | Test 24 | 25 | Sub 26 | 单元测试(Sub) 27 | XXX(Sub) 28 | 29 | test_main_label 30 | test_sub_label 31 | 32 | test_main_filter 33 | test_sub_filter 34 | 35 | test_main_string 36 | test_sub_string 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 19 | 20 | 24 | 35 | 36 | 43 | 44 | 48 | 49 | 58 | 59 | 68 | 69 | 78 | 79 | 90 | 95 | 96 | 106 | 107 | 110 | 111 | 118 | 119 | 124 | 125 | 129 | 130 | 138 | 139 | 147 | 148 | 155 | 156 | 163 | 164 | 173 | 174 | 181 | 182 | 191 | 192 | 198 | 199 | 208 | 209 | 210 | -------------------------------------------------------------------------------- /app/src/main/res/xml/test_provider.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | apply from: 'files/default.gradle' 2 | 3 | buildscript { 4 | repositories { 5 | maven { url 'https://maven.aliyun.com/repository/public' } 6 | maven { url 'https://maven.aliyun.com/repository/google' } 7 | maven { url 'https://www.jitpack.io' } 8 | maven { url 'https://maven.aliyun.com/repository/gradle-plugin' } 9 | } 10 | 11 | dependencies { 12 | // classpath "org.sonarsource.scanner.gradle:sonarqube-gradle-plugin:2.6" 13 | classpath 'com.android.tools.build:gradle:4.2.0' 14 | } 15 | } 16 | 17 | task clean(type: Delete) { 18 | delete rootProject.buildDir 19 | } 20 | -------------------------------------------------------------------------------- /cmpt-cocollider/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply from: '../../../default.gradle' 3 | 4 | android { 5 | def globalConfig = rootProject.extensions.getByName("ext") 6 | buildToolsVersion globalConfig.getAt("androidBuildToolsVersion") 7 | compileSdkVersion globalConfig.getAt("androidCompileSdkVersion") 8 | 9 | defaultConfig { 10 | minSdkVersion globalConfig.getAt("androidMinSdkVersion") 11 | targetSdkVersion globalConfig.getAt("androidTargetSdkVersion") 12 | // ndk { 13 | // abiFilters "armeabi-v7a", "arm64-v8a" 14 | // } 15 | } 16 | 17 | // externalNativeBuild { 18 | // ndkBuild { 19 | // path file('src/main/jni/Android.mk') 20 | // } 21 | // } 22 | 23 | sourceSets { 24 | main { 25 | assets.srcDirs = ['assets'] 26 | jniLibs.srcDirs = ['src/main/libs'] 27 | } 28 | } 29 | 30 | compileOptions { 31 | sourceCompatibility JavaVersion.VERSION_1_8 32 | targetCompatibility JavaVersion.VERSION_1_8 33 | } 34 | } 35 | 36 | repositories { 37 | flatDir { 38 | dirs '../../../out', 'libs' 39 | } 40 | } 41 | 42 | dependencies { 43 | implementation fileTree(dir: 'libs', include: ['*.jar']) 44 | debugImplementation (name: 'cmpt/common/debug/cmpt-utils', ext: 'aar') 45 | releaseImplementation (name: 'cmpt/common/release/cmpt-utils', ext: 'aar') 46 | } 47 | -------------------------------------------------------------------------------- /cmpt-cocollider/mk.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # @ date: 2020.07.27 17:19 4 | # 5 | 6 | set -u 7 | set -e 8 | 9 | LOCAL_PATH=`pwd` 10 | OUT_PATH=$1 11 | BUILD_TYPE=$2 12 | MODULE_NAME=$3 13 | 14 | # ---------------------------------------------------------------- 15 | # build jni 16 | # ---------------------------------------------------------------- 17 | cd src/main 18 | ./mk.sh $OUT_PATH $BUILD_TYPE 19 | cd - 20 | 21 | # ---------------------------------------------------------------- 22 | # build module 23 | # ---------------------------------------------------------------- 24 | cd .. 25 | if [ $BUILD_TYPE = debug ] ; then 26 | # ./gradlew $MODULE_NAME:testDebug 27 | ./gradlew :$MODULE_NAME:assembleDebug 28 | else 29 | # ./gradlew $MODULE_NAME:testRelease 30 | ./gradlew :$MODULE_NAME:assembleRelease 31 | fi 32 | cd - 33 | 34 | # ---------------------------------------------------------------- 35 | # build end 36 | # ---------------------------------------------------------------- 37 | cp -f $LOCAL_PATH/build/outputs/aar/*-$BUILD_TYPE.aar $OUT_PATH/$MODULE_NAME.aar 38 | -------------------------------------------------------------------------------- /cmpt-cocollider/pom.json: -------------------------------------------------------------------------------- 1 | { 2 | "mvn": [ 3 | { 4 | "groupId": "com.iofomo.android", 5 | "artifactId": "cmpt-cocollider", 6 | "version": "1.0.0", 7 | "file": "build/outputs/aar/cmpt-cocollider-release.aar", 8 | "packaing": "aar" 9 | } 10 | ] 11 | } -------------------------------------------------------------------------------- /cmpt-cocollider/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /cmpt-cocollider/src/main/java/com/ifma/cmpt/cocollider/CoColliderManager.java: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.cocollider; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.text.TextUtils; 6 | 7 | import com.ifma.cmpt.utils.CmnInitor; 8 | import com.ifma.cmpt.utils.FileUtils; 9 | import com.ifma.cmpt.utils.ReflectUtils; 10 | 11 | import java.io.BufferedReader; 12 | import java.io.File; 13 | import java.io.FileInputStream; 14 | import java.io.FileOutputStream; 15 | import java.io.InputStream; 16 | import java.io.InputStreamReader; 17 | import java.io.OutputStream; 18 | import java.lang.reflect.Field; 19 | import java.lang.reflect.Method; 20 | import java.util.ArrayList; 21 | import java.util.List; 22 | 23 | public class CoColliderManager { 24 | private static final String TAG = "CoColliderManager"; 25 | public static final String KEY_IN = "key-in"; 26 | public static final String KEY_OUT = "key-out"; 27 | 28 | public static void handleCallEvent(Context ctx, Bundle inData, Bundle replayData) throws Throwable { 29 | String fileIn = inData.getString(KEY_IN); 30 | File fileOut = new File(ctx.getExternalCacheDir().getParent(), "cocollider-run.txt"); 31 | 32 | InputStream is = null; 33 | OutputStream os = null; 34 | try { 35 | is = new FileInputStream(fileIn); 36 | os = new FileOutputStream(fileOut); 37 | if (doParse(is, os)) { 38 | replayData.putString(KEY_OUT, fileOut.getAbsolutePath()); 39 | } 40 | } catch (Throwable e) { 41 | e.printStackTrace(); 42 | } finally { 43 | FileUtils.closeQuietly(is); 44 | FileUtils.closeQuietly(os); 45 | } 46 | } 47 | 48 | private static byte[] sOKBytes = "[OK], ".getBytes(); 49 | private static byte[] sFailBytes = "[Fail]".getBytes(); 50 | private static int CLASS_START = 1; 51 | private static int NATIVE_START = 2; 52 | 53 | public static boolean doParse(InputStream is, OutputStream os) throws Throwable { 54 | int status = 0; 55 | String line, lastClassName = null; 56 | Class lastClass = null; 57 | BufferedReader reader = new BufferedReader(new InputStreamReader(is)); 58 | while (null != (line = reader.readLine())) { 59 | os.write(line.getBytes()); 60 | os.write('\n'); 61 | if (line.startsWith("~")) {// native 62 | status = NATIVE_START; 63 | lastClassName = line.substring(1).trim(); 64 | if (0L != CmnInitor.getLibSym(lastClassName, null)) { 65 | os.write(sOKBytes); 66 | os.write(lastClass.toGenericString().getBytes()); 67 | os.write('\n'); 68 | } else { 69 | os.write(sFailBytes); 70 | os.write('\n'); 71 | } 72 | } else if (line.startsWith("=")) {// class 73 | status = CLASS_START; 74 | lastClassName = line.substring(1).trim(); 75 | lastClass = ReflectUtils.findClass(lastClassName); 76 | if (null != lastClass) { 77 | os.write(sOKBytes); 78 | os.write(lastClass.toGenericString().getBytes()); 79 | os.write('\n'); 80 | } else { 81 | os.write(sFailBytes); 82 | os.write('\n'); 83 | } 84 | } else if (line.startsWith("+")) {// method 85 | if (status == CLASS_START) { 86 | List mm = reflectMethod(lastClass, line.substring(1).trim()); 87 | if (null == mm) { 88 | os.write(sFailBytes); 89 | os.write('\n'); 90 | } else { 91 | for (String m : mm) { 92 | os.write(m.getBytes()); 93 | os.write('\n'); 94 | } 95 | } 96 | } else { 97 | if (0L != CmnInitor.getLibSym(lastClassName, line.substring(1).trim())) { 98 | os.write(sOKBytes); 99 | os.write(lastClassName.getBytes()); 100 | os.write('\n'); 101 | } else { 102 | os.write(sFailBytes); 103 | os.write('\n'); 104 | } 105 | } 106 | } else if (line.startsWith("-")) {// field 107 | if (status == CLASS_START) { 108 | List ff = reflectField(lastClass, line.substring(1).trim()); 109 | if (null == ff) { 110 | os.write(sFailBytes); 111 | os.write('\n'); 112 | } else { 113 | for (String f : ff) { 114 | os.write(f.getBytes()); 115 | os.write('\n'); 116 | } 117 | } 118 | } else { 119 | if (0L != CmnInitor.getLibSym(lastClassName, line.substring(1).trim())) { 120 | os.write(sOKBytes); 121 | os.write(lastClassName.getBytes()); 122 | os.write('\n'); 123 | } else { 124 | os.write(sFailBytes); 125 | os.write('\n'); 126 | } 127 | } 128 | } 129 | } 130 | return false; 131 | } 132 | 133 | private static List reflectMethod(Class cls, String method) { 134 | if (null == cls) return null; 135 | 136 | List ss = new ArrayList<>(); 137 | try { 138 | Method[] mm = cls.getDeclaredMethods(); 139 | for (Method m : mm) { 140 | if (!m.isAccessible()) m.setAccessible(true); 141 | if (TextUtils.equals(method, "*") || TextUtils.equals(method, m.getName())) { 142 | ss.add(m.toGenericString()); 143 | } 144 | } 145 | return 0 < ss.size() ? ss : null; 146 | } catch (Throwable e) { 147 | e.printStackTrace(); 148 | } 149 | return null; 150 | } 151 | 152 | private static List reflectField(Class cls, String field) { 153 | if (null == cls) return null; 154 | 155 | List ss = new ArrayList<>(); 156 | try { 157 | if (TextUtils.equals(field, "*")) { 158 | Field[] ff = cls.getDeclaredFields(); 159 | for (Field f : ff) { 160 | if (!f.isAccessible()) f.setAccessible(true); 161 | ss.add(f.toGenericString()); 162 | } 163 | } else { 164 | Field f = cls.getDeclaredField(field); 165 | if (null == f) return null; 166 | if (!f.isAccessible()) f.setAccessible(true); 167 | ss.add(f.toGenericString()); 168 | } 169 | return 0 < ss.size() ? ss : null; 170 | } catch (Throwable e) { 171 | e.printStackTrace(); 172 | } 173 | return null; 174 | } 175 | } 176 | -------------------------------------------------------------------------------- /cmpt-cocollider/src/main/mk.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -u 3 | set -e 4 | 5 | LOCAL_PATH=`pwd` 6 | OUT_PATH=$1 7 | BUILD_TYPE=$2 8 | 9 | # ------------------------------------------------------------------------------------------------------ 10 | # ------------------------------------------------------------------------------------------------------ 11 | #rm -rf ${OUT_PATH}/libs 12 | #mv libs ${OUT_PATH} 13 | 14 | # ------------------------------------------------------------------------------------------------------ 15 | rm -rf obj 16 | #rm -rf libs 17 | -------------------------------------------------------------------------------- /cmpt-fireyer/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | apply from: '../files/default.gradle' 3 | 4 | android { 5 | def globalConfig = rootProject.extensions.getByName("ext") 6 | buildToolsVersion globalConfig.getAt("androidBuildToolsVersion") 7 | compileSdkVersion globalConfig.getAt("androidCompileSdkVersion") 8 | 9 | defaultConfig { 10 | minSdkVersion globalConfig.getAt("androidMinSdkVersion") 11 | targetSdkVersion globalConfig.getAt("androidTargetSdkVersion") 12 | // ndk { 13 | // abiFilters "armeabi-v7a", "arm64-v8a" 14 | // } 15 | } 16 | 17 | // externalNativeBuild { 18 | // ndkBuild { 19 | // path file('src/main/jni/Android.mk') 20 | // } 21 | // } 22 | 23 | sourceSets { 24 | main { 25 | assets.srcDirs = ['assets'] 26 | jniLibs.srcDirs = ['src/main/libs'] 27 | } 28 | } 29 | 30 | compileOptions { 31 | sourceCompatibility JavaVersion.VERSION_1_8 32 | targetCompatibility JavaVersion.VERSION_1_8 33 | } 34 | } 35 | 36 | repositories { 37 | flatDir { 38 | dirs '../libs' 39 | } 40 | } 41 | 42 | dependencies { 43 | implementation fileTree(dir: 'libs', include: ['*.jar']) 44 | implementation (name: 'cmpt-utils', ext: 'aar') 45 | } 46 | -------------------------------------------------------------------------------- /cmpt-fireyer/mk.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | # 3 | # @ date: 2020.07.27 17:19 4 | # 5 | 6 | set -u 7 | set -e 8 | 9 | LOCAL_PATH=`pwd` 10 | OUT_PATH=$1 11 | BUILD_TYPE=$2 12 | MODULE_NAME=$3 13 | 14 | # ---------------------------------------------------------------- 15 | # build jni 16 | # ---------------------------------------------------------------- 17 | cd src/main 18 | ./mk.sh $OUT_PATH $BUILD_TYPE 19 | cd - 20 | 21 | # ---------------------------------------------------------------- 22 | # build module 23 | # ---------------------------------------------------------------- 24 | cd .. 25 | if [ $BUILD_TYPE = debug ] ; then 26 | # ./gradlew $MODULE_NAME:testDebug 27 | ./gradlew :$MODULE_NAME:assembleDebug 28 | else 29 | # ./gradlew $MODULE_NAME:testRelease 30 | ./gradlew :$MODULE_NAME:assembleRelease 31 | fi 32 | cd - 33 | 34 | # ---------------------------------------------------------------- 35 | # build end 36 | # ---------------------------------------------------------------- 37 | cp -f $LOCAL_PATH/build/outputs/aar/*-$BUILD_TYPE.aar $OUT_PATH/$MODULE_NAME.aar 38 | -------------------------------------------------------------------------------- /cmpt-fireyer/pom.json: -------------------------------------------------------------------------------- 1 | { 2 | "mvn": [ 3 | { 4 | "groupId": "com.iofomo.android", 5 | "artifactId": "cmpt-fireyer", 6 | "version": "1.0.0", 7 | "file": "build/outputs/aar/cmpt-fireyer-release.aar", 8 | "packaing": "aar" 9 | } 10 | ] 11 | } -------------------------------------------------------------------------------- /cmpt-fireyer/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /cmpt-fireyer/src/main/java/com/ifma/cmpt/fireyer/FireyerNative.java: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.fireyer; 2 | 3 | /** 4 | * @Brief: say something 5 | * @Date: 2024.01.08 16:52:52 6 | */ 7 | 8 | public final class FireyerNative { 9 | public static final int TYPE_GET_THREAD = 1; 10 | public static final int TYPE_GET_PROC = 2; 11 | public static final int TYPE_FILE_LIST = 3; 12 | public static final int TYPE_GET_STACK = 4; 13 | public static final int TYPE_GET_PROP_POPEN = 5; 14 | public static final int TYPE_GET_PROP_SPG = 6; 15 | public static final int TYPE_GET_PROP_SPRC = 7; 16 | 17 | static { 18 | try { 19 | System.loadLibrary("fireyer-jni"); 20 | } catch (Throwable e) { 21 | e.printStackTrace(); 22 | } 23 | } 24 | 25 | public static native int svc_open(String name, boolean isRead); 26 | public static native int svc_read(int fd, byte[] buffer, int bufferSize); 27 | public static native int svc_write(int fd, byte[] buffer, int bufferSize); 28 | public static native int svc_close(int fd); 29 | 30 | /** 31 | * [0~8]: mtime, ctime, blksize, blocks, gid, uid, inode, mode, size 32 | * **/ 33 | public static native Object[] svc_stat(String name); 34 | public static native String svc_readlink(int fd); 35 | 36 | public static native Object callNative(int type, Object arg); 37 | } 38 | -------------------------------------------------------------------------------- /cmpt-fireyer/src/main/java/com/ifma/cmpt/fireyer/FireyerUtils.java: -------------------------------------------------------------------------------- 1 | package com.ifma.cmpt.fireyer; 2 | 3 | import android.text.TextUtils; 4 | 5 | import com.ifma.cmpt.utils.CipherUtils; 6 | 7 | import java.io.Closeable; 8 | import java.io.File; 9 | import java.security.MessageDigest; 10 | 11 | /** 12 | * @Brief: say something 13 | * @Date: 2024.01.08 16:52:52 14 | */ 15 | 16 | public class FireyerUtils { 17 | private static final String TAG = "FireyerManager"; 18 | 19 | public static String md5File(String file, boolean checkFileName) { 20 | int fd = -1; 21 | try { 22 | MessageDigest md = MessageDigest.getInstance("MD5"); 23 | fd = FireyerNative.svc_open(file, true); 24 | if (fd < 0) return null; 25 | 26 | if (checkFileName && !TextUtils.equals(file, FireyerNative.svc_readlink(fd))) { 27 | return null; 28 | } 29 | 30 | int len; 31 | byte[] buffer = new byte[8192]; 32 | while (0 < (len = FireyerNative.svc_read(fd, buffer, buffer.length))) { 33 | md.update(buffer, 0, len); 34 | } 35 | return CipherUtils.bytesToHexString(md.digest()); 36 | } catch (Throwable e) { 37 | e.printStackTrace(); 38 | } finally { 39 | if (0 <= fd) FireyerNative.svc_close(fd); 40 | } 41 | return null; 42 | } 43 | 44 | public static String readFile(String file, boolean checkFileName) { 45 | int fd = -1; 46 | try { 47 | StringBuilder sb = new StringBuilder(); 48 | fd = FireyerNative.svc_open(file, true); 49 | if (fd < 0) return null; 50 | 51 | if (checkFileName && !TextUtils.equals(file, FireyerNative.svc_readlink(fd))) { 52 | return null; 53 | } 54 | 55 | int len; 56 | byte[] buffer = new byte[8192]; 57 | while (0 < (len = FireyerNative.svc_read(fd, buffer, buffer.length))) { 58 | sb.append(new String(buffer, 0, len)); 59 | } 60 | return sb.toString(); 61 | } catch (Throwable e) { 62 | e.printStackTrace(); 63 | } finally { 64 | if (0 <= fd) FireyerNative.svc_close(fd); 65 | } 66 | return null; 67 | } 68 | 69 | public static int[] getThreads() { 70 | return (int[])FireyerNative.callNative(FireyerNative.TYPE_GET_THREAD, null); 71 | } 72 | 73 | public static String getThreadName(int pid, int tid) { 74 | String s = readFile("/proc/" + pid + "/task/" + tid + "/status", true); 75 | if (TextUtils.isEmpty(s)) return null; 76 | String[] lines = s.split("\n"); 77 | for (String line : lines) { 78 | line = line.trim(); 79 | if (!line.startsWith("Name:")) continue; 80 | return line.substring("Name:".length()).trim(); 81 | } 82 | return null; 83 | } 84 | 85 | public static int[] getPids() { 86 | return (int[])FireyerNative.callNative(FireyerNative.TYPE_GET_PROC, android.os.Process.myUid()); 87 | } 88 | 89 | public static String getProceName(int pid) { 90 | String s = readFile("/proc/" + pid + "/cmdline", true); 91 | if (!TextUtils.isEmpty(s)) return s.trim(); 92 | 93 | s = readFile("/proc/" + pid + "/status", true); 94 | String[] items = s.split("\n"); 95 | for (String line : items) { 96 | if (line.startsWith("Name:")) { 97 | return line.substring(5).trim(); 98 | } 99 | } 100 | return null; 101 | } 102 | 103 | public static void closeQuietly(Closeable closeable){ 104 | if (closeable != null){ 105 | try { 106 | closeable.close(); 107 | }catch (Throwable t){} 108 | } 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /cmpt-fireyer/src/main/jni/Android.mk: -------------------------------------------------------------------------------- 1 | LOCAL_PATH := $(call my-dir) 2 | 3 | __SRC_FILES := \ 4 | src/fireyer_main.cpp \ 5 | src/fireyer_native.cpp \ 6 | 7 | ########################### build for .so 8 | include $(CLEAR_VARS) 9 | LOCAL_MODULE := libfireyer-jni 10 | LOCAL_C_INCLUDES += $(LOCAL_PATH)/inc 11 | LOCAL_CFLAGS += -Os -fvisibility=hidden -Wall -Werror 12 | LOCAL_SRC_FILES += $(__SRC_FILES) 13 | LOCAL_LDLIBS += -llog -L$(LOCAL_SHARE_LIB_PATH) -lstdc++ 14 | LOCAL_CFLAGS += -DHAVE_PTHREADS 15 | include $(BUILD_SHARED_LIBRARY) 16 | -------------------------------------------------------------------------------- /cmpt-fireyer/src/main/jni/Application.mk: -------------------------------------------------------------------------------- 1 | NDK_MODULE_PATH := $(call my-dir) 2 | APP_OPTIM := release 3 | APP_ABI := armeabi-v7a arm64-v8a 4 | APP_PLATFORM := android-28 5 | APP_STL := c++_static 6 | APP_MODULES := fireyer-jni 7 | #APP_CPPFLAGS += -fpermissive 8 | -------------------------------------------------------------------------------- /cmpt-fireyer/src/main/jni/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.6.0) 2 | project(ifma_fireyer_jni) 3 | 4 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") 5 | # self include 6 | include_directories("inc") 7 | 8 | file(GLOB foo_sources . *.cpp *.h 9 | inc/*.h 10 | src/*.cpp 11 | ) 12 | 13 | set(SOURCE_FILES ${foo_sources}) 14 | add_executable(${PROJECT_NAME} ${SOURCE_FILES}) 15 | -------------------------------------------------------------------------------- /cmpt-fireyer/src/main/jni/inc/arch.h: -------------------------------------------------------------------------------- 1 | /* -*- c-set-style: "K&R"; c-basic-offset: 8 -*- 2 | * 3 | * This file is part of PRoot. 4 | * 5 | * Copyright (C) 2015 STMicroelectronics 6 | * 7 | * This program is free software; you can redistribute it and/or 8 | * modify it under the terms of the GNU General Public License as 9 | * published by the Free Software Foundation; either version 2 of the 10 | * License, or (at your option) any later version. 11 | * 12 | * This program is distributed in the hope that it will be useful, but 13 | * WITHOUT ANY WARRANTY; without even the implied warranty of 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 | * General Public License for more details. 16 | * 17 | * You should have received a copy of the GNU General Public License 18 | * along with this program; if not, write to the Free Software 19 | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 20 | * 02110-1301 USA. 21 | */ 22 | 23 | #ifndef ARCH_H 24 | #define ARCH_H 25 | 26 | #ifndef NO_LIBC_HEADER 27 | #include /* linux.git:c0a3a20b */ 28 | #include /* AUDIT_ARCH_*, */ 29 | #endif 30 | 31 | typedef unsigned long word_t; 32 | typedef unsigned char byte_t; 33 | 34 | #define SYSCALL_AVOIDER ((word_t) -1) 35 | #define SYSTRAP_NUM SYSARG_NUM 36 | #define STACK_ALIGNMENT 16 37 | 38 | #define OFFSETOF_STATX_UID 20 39 | #define OFFSETOF_STATX_GID 24 40 | 41 | #if !defined(ARCH_X86_64) && !defined(ARCH_ARM_EABI) && !defined(ARCH_X86) && !defined(ARCH_SH4) 42 | # if defined(__x86_64__) 43 | # define ARCH_X86_64 1 44 | # elif defined(__ARM_EABI__) 45 | # define ARCH_ARM_EABI 1 46 | # elif defined(__aarch64__) 47 | # define ARCH_ARM64 1 48 | # elif defined(__arm__) 49 | # error "Only EABI is currently supported for ARM" 50 | # elif defined(__i386__) 51 | # define ARCH_X86 1 52 | # elif defined(__SH4__) 53 | # define ARCH_SH4 1 54 | # else 55 | # error "Unsupported architecture" 56 | # endif 57 | #endif 58 | 59 | /* Architecture specific definitions. */ 60 | #if defined(ARCH_X86_64) 61 | 62 | #define SYSNUMS_HEADER1 "syscall/sysnums-x86_64.h" 63 | #define SYSNUMS_HEADER2 "syscall/sysnums-i386.h" 64 | #define SYSNUMS_HEADER3 "syscall/sysnums-x32.h" 65 | 66 | #define SYSNUMS_ABI1 sysnums_x86_64 67 | #define SYSNUMS_ABI2 sysnums_i386 68 | #define SYSNUMS_ABI3 sysnums_x32 69 | 70 | #undef SYSTRAP_NUM 71 | #define SYSTRAP_NUM SYSARG_RESULT 72 | #define SYSTRAP_SIZE 2 73 | 74 | #define SECCOMP_ARCHS { \ 75 | { .value = AUDIT_ARCH_X86_64, .nb_abis = 2, .abis = { ABI_DEFAULT, ABI_3 } }, \ 76 | { .value = AUDIT_ARCH_I386, .nb_abis = 1, .abis = { ABI_2 } }, \ 77 | } 78 | 79 | #define HOST_ELF_MACHINE {62, 3, 6, 0} 80 | #define RED_ZONE_SIZE 128 81 | #define OFFSETOF_STAT_UID_32 24 82 | #define OFFSETOF_STAT_GID_32 28 83 | 84 | #define LOADER_ADDRESS 0x600000000000 85 | #define HAS_LOADER_32BIT true 86 | 87 | #define EXEC_PIC_ADDRESS 0x500000000000 88 | #define INTERP_PIC_ADDRESS 0x6f0000000000 89 | #define EXEC_PIC_ADDRESS_32 0x0f000000 90 | #define INTERP_PIC_ADDRESS_32 0xaf000000 91 | 92 | #elif defined(ARCH_ARM_EABI) 93 | 94 | #define SYSNUMS_HEADER1 "syscall/sysnums-arm.h" 95 | #define SYSNUMS_ABI1 sysnums_arm 96 | 97 | #define SYSTRAP_SIZE 4 98 | 99 | #define SECCOMP_ARCHS { { .value = AUDIT_ARCH_ARM, .nb_abis = 1, .abis = { ABI_DEFAULT } } } 100 | 101 | #define user_regs_struct user_regs 102 | #define HOST_ELF_MACHINE {40, 0}; 103 | #define RED_ZONE_SIZE 0 104 | #define OFFSETOF_STAT_UID_32 0 105 | #define OFFSETOF_STAT_GID_32 0 106 | #define EM_ARM 40 107 | 108 | #define LOADER_ADDRESS 0x10000000 109 | 110 | #define EXEC_PIC_ADDRESS 0x0f000000 111 | #define INTERP_PIC_ADDRESS 0x1f000000 112 | 113 | #elif defined(ARCH_ARM64) 114 | 115 | #define SYSNUMS_HEADER1 "syscall/sysnums-arm64.h" 116 | #define SYSNUMS_ABI1 sysnums_arm64 117 | 118 | #define SYSTRAP_SIZE 4 119 | 120 | #ifndef AUDIT_ARCH_AARCH64 121 | #define AUDIT_ARCH_AARCH64 (EM_AARCH64 | __AUDIT_ARCH_64BIT | __AUDIT_ARCH_LE) 122 | #endif 123 | 124 | #define SECCOMP_ARCHS { { .value = AUDIT_ARCH_AARCH64, .nb_abis = 1, .abis = { ABI_DEFAULT } } } 125 | 126 | #define HOST_ELF_MACHINE {183, 0}; 127 | #define RED_ZONE_SIZE 0 128 | #define OFFSETOF_STAT_UID_32 0 129 | #define OFFSETOF_STAT_GID_32 0 130 | 131 | #define LOADER_ADDRESS 0x2000000000 132 | #define EXEC_PIC_ADDRESS 0x3000000000 133 | #define INTERP_PIC_ADDRESS 0x3f00000000 134 | 135 | #elif defined(ARCH_X86) 136 | 137 | #define SYSNUMS_HEADER1 "syscall/sysnums-i386.h" 138 | #define SYSNUMS_ABI1 sysnums_i386 139 | 140 | #undef SYSTRAP_NUM 141 | #define SYSTRAP_NUM SYSARG_RESULT 142 | #define SYSTRAP_SIZE 2 143 | 144 | #define SECCOMP_ARCHS { { .value = AUDIT_ARCH_I386, .nb_abis = 1, .abis = { ABI_DEFAULT } } } 145 | 146 | #define HOST_ELF_MACHINE {3, 6, 0}; 147 | #define RED_ZONE_SIZE 0 148 | #define OFFSETOF_STAT_UID_32 0 149 | #define OFFSETOF_STAT_GID_32 0 150 | 151 | #define LOADER_ADDRESS 0xa0000000 152 | #define LOADER_ARCH_CFLAGS -mregparm=3 153 | 154 | #define EXEC_PIC_ADDRESS 0x0f000000 155 | #define INTERP_PIC_ADDRESS 0xaf000000 156 | 157 | #elif defined(ARCH_SH4) 158 | 159 | #define SYSNUMS_HEADER1 "syscall/sysnums-sh4.h" 160 | #define SYSNUMS_ABI1 sysnums_sh4 161 | 162 | #define SYSTRAP_SIZE 2 163 | 164 | #define SECCOMP_ARCHS { } 165 | 166 | #define user_regs_struct pt_regs 167 | #define HOST_ELF_MACHINE {42, 0}; 168 | #define RED_ZONE_SIZE 0 169 | #define OFFSETOF_STAT_UID_32 0 170 | #define OFFSETOF_STAT_GID_32 0 171 | #define NO_MISALIGNED_ACCESS 1 172 | 173 | #else 174 | 175 | #error "Unsupported architecture" 176 | 177 | #endif 178 | 179 | #endif /* ARCH_H */ 180 | -------------------------------------------------------------------------------- /cmpt-fireyer/src/main/jni/inc/assembly-arm.h: -------------------------------------------------------------------------------- 1 | /* According to the ARM EABI, all registers have undefined values at 2 | * program startup except: 3 | * 4 | * - the instruction pointer (r15) 5 | * - the stack pointer (r13) 6 | * - the rtld_fini pointer (r0) 7 | */ 8 | 9 | #include 10 | #include "arch.h" 11 | 12 | #define BRANCH(stack_pointer, destination) do { \ 13 | asm volatile ( \ 14 | "// Restore initial stack pointer. \n\t" \ 15 | "mov sp, %0 \n\t" \ 16 | " \n\t" \ 17 | "// Clear rtld_fini. \n\t" \ 18 | "mov r0, #0 \n\t" \ 19 | " \n\t" \ 20 | "// Start the program. \n\t" \ 21 | "mov pc, %1 \n" \ 22 | : /* no output */ \ 23 | : "r" (stack_pointer), "r" (destination) \ 24 | : "memory", "sp", "r0", "pc"); \ 25 | __builtin_unreachable(); \ 26 | } while (0) 27 | 28 | #define PREPARE_ARGS_1(arg1_) \ 29 | register word_t arg1 asm("r0") = (word_t)arg1_; 30 | 31 | #define PREPARE_ARGS_2(arg1_, arg2_) \ 32 | PREPARE_ARGS_1(arg1_) \ 33 | register word_t arg2 asm("r1") = (word_t)arg2_; 34 | 35 | #define PREPARE_ARGS_3(arg1_, arg2_, arg3_) \ 36 | PREPARE_ARGS_2(arg1_, arg2_) \ 37 | register word_t arg3 asm("r2") = (word_t)arg3_; 38 | 39 | #define PREPARE_ARGS_4(arg1_, arg2_, arg3_, arg4_) \ 40 | PREPARE_ARGS_3(arg1_, arg2_, arg3_) \ 41 | register word_t arg4 asm("r3") = (word_t)arg4_; 42 | 43 | #define PREPARE_ARGS_5(arg1_, arg2_, arg3_, arg4_, arg5_) \ 44 | PREPARE_ARGS_4(arg1_, arg2_, arg3_, arg4_) \ 45 | register word_t arg5 asm("r4") = (word_t)arg5_; 46 | 47 | #define PREPARE_ARGS_6(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_) \ 48 | PREPARE_ARGS_5(arg1_, arg2_, arg3_, arg4_, arg5_) \ 49 | register word_t arg6 asm("r5") = (word_t)arg6_; 50 | 51 | #define OUTPUT_CONTRAINTS_1 \ 52 | "r" (arg1) 53 | 54 | #define OUTPUT_CONTRAINTS_2 \ 55 | OUTPUT_CONTRAINTS_1, \ 56 | "r" (arg2) 57 | 58 | #define OUTPUT_CONTRAINTS_3 \ 59 | OUTPUT_CONTRAINTS_2, \ 60 | "r" (arg3) 61 | 62 | #define OUTPUT_CONTRAINTS_4 \ 63 | OUTPUT_CONTRAINTS_3, \ 64 | "r" (arg4) 65 | 66 | #define OUTPUT_CONTRAINTS_5 \ 67 | OUTPUT_CONTRAINTS_4, \ 68 | "r" (arg5) 69 | 70 | #define OUTPUT_CONTRAINTS_6 \ 71 | OUTPUT_CONTRAINTS_5, \ 72 | "r" (arg6) 73 | 74 | #define SVC_SYSCALL(number_, nb_args, args...) \ 75 | ({ \ 76 | register word_t number asm("r7") = number_; \ 77 | register word_t result asm("r0"); \ 78 | PREPARE_ARGS_##nb_args(args) \ 79 | asm volatile ( \ 80 | "svc #0x00000000 \n\t" \ 81 | : "=r" (result) \ 82 | : "r" (number), \ 83 | OUTPUT_CONTRAINTS_##nb_args \ 84 | : "memory"); \ 85 | result; \ 86 | }) 87 | 88 | struct linux_dirent { 89 | unsigned long d_ino;/* Inode number */ 90 | unsigned long d_off;/* Offset to next linux dirent */ 91 | unsigned short d_reclen;/* Length of this linux dirent */ 92 | char d_name[];/* Filename (null-terminated) */ 93 | }; 94 | 95 | #define SVC_OPENAT 322 // 0x142 96 | #define SVC_CLOSE 6 // 0x6 97 | #define SVC_GETDENTS 217 // 0xd9 98 | #define SVC_READ 3 // 0x3 99 | #define SVC_WRITE 4 // 0x4 100 | #define SVC_READLINKAT 332 // 0x14c 101 | #define SVC_FSTATAT 327 // 0x147 102 | -------------------------------------------------------------------------------- /cmpt-fireyer/src/main/jni/inc/assembly-arm64.h: -------------------------------------------------------------------------------- 1 | /* According to the ARM64 EABI, all registers have undefined values at 2 | * program startup except: 3 | * 4 | * - the instruction pointer (pc) 5 | * - the stack pointer (sp) 6 | * - the rtld_fini pointer (x0) 7 | */ 8 | 9 | #include 10 | #include "arch.h" 11 | 12 | #define BRANCH(stack_pointer, destination) do { \ 13 | asm volatile ( \ 14 | "// Restore initial stack pointer. \n\t" \ 15 | "mov sp, %0 \n\t" \ 16 | " \n\t" \ 17 | "// Clear rtld_fini. \n\t" \ 18 | "mov x0, #0 \n\t" \ 19 | " \n\t" \ 20 | "// Start the program. \n\t" \ 21 | "br %1 \n" \ 22 | : /* no output */ \ 23 | : "r" (stack_pointer), "r" (destination) \ 24 | : "memory", "sp", "x0"); \ 25 | __builtin_unreachable(); \ 26 | } while (0) 27 | 28 | #define PREPARE_ARGS_1(arg1_) \ 29 | register word_t arg1 asm("x0") = (word_t)arg1_; 30 | 31 | #define PREPARE_ARGS_2(arg1_, arg2_) \ 32 | PREPARE_ARGS_1(arg1_) \ 33 | register word_t arg2 asm("x1") = (word_t)arg2_; 34 | 35 | #define PREPARE_ARGS_3(arg1_, arg2_, arg3_) \ 36 | PREPARE_ARGS_2(arg1_, arg2_) \ 37 | register word_t arg3 asm("x2") = (word_t)arg3_; 38 | 39 | #define PREPARE_ARGS_4(arg1_, arg2_, arg3_, arg4_) \ 40 | PREPARE_ARGS_3(arg1_, arg2_, arg3_) \ 41 | register word_t arg4 asm("x3") = (word_t)arg4_; 42 | 43 | #define PREPARE_ARGS_5(arg1_, arg2_, arg3_, arg4_, arg5_) \ 44 | PREPARE_ARGS_4(arg1_, arg2_, arg3_, arg4_) \ 45 | register word_t arg5 asm("x4") = (word_t)arg5_; 46 | 47 | #define PREPARE_ARGS_6(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_) \ 48 | PREPARE_ARGS_5(arg1_, arg2_, arg3_, arg4_, arg5_) \ 49 | register word_t arg6 asm("x5") = (word_t)arg6_; 50 | 51 | #define OUTPUT_CONTRAINTS_1 \ 52 | "r" (arg1) \ 53 | 54 | #define OUTPUT_CONTRAINTS_2 \ 55 | OUTPUT_CONTRAINTS_1, \ 56 | "r" (arg2) \ 57 | 58 | #define OUTPUT_CONTRAINTS_3 \ 59 | OUTPUT_CONTRAINTS_2, \ 60 | "r" (arg3) 61 | 62 | #define OUTPUT_CONTRAINTS_4 \ 63 | OUTPUT_CONTRAINTS_3, \ 64 | "r" (arg4) \ 65 | 66 | #define OUTPUT_CONTRAINTS_5 \ 67 | OUTPUT_CONTRAINTS_4, \ 68 | "r" (arg5) \ 69 | 70 | #define OUTPUT_CONTRAINTS_6 \ 71 | OUTPUT_CONTRAINTS_5, \ 72 | "r" (arg6) \ 73 | 74 | #define SVC_SYSCALL(number_, nb_args, args...) \ 75 | ({ \ 76 | register word_t number asm("x8") = number_; \ 77 | register word_t result asm("x0"); \ 78 | PREPARE_ARGS_##nb_args(args) \ 79 | asm volatile ( \ 80 | "svc #0x00000000 \n\t" \ 81 | : "=r" (result) \ 82 | : "r" (number), \ 83 | OUTPUT_CONTRAINTS_##nb_args \ 84 | : "memory"); \ 85 | result; \ 86 | }) 87 | 88 | struct linux_dirent { 89 | ino64_t d_ino; /* Inode number */ 90 | off64_t d_off; /* Offset to the next linux_dirent */ 91 | unsigned short d_reclen; /* Length of this linux_dirent */ 92 | unsigned char d_type; /* File type */ 93 | char d_name[]; /* Filename (null-terminated) */ 94 | }; 95 | 96 | #define SVC_OPENAT 56 // 0x38 97 | #define SVC_CLOSE 57 // 0x39 98 | #define SVC_GETDENTS 61 // 0x3d 99 | #define SVC_READ 63 // 0x3f 100 | #define SVC_WRITE 64 // 0x40 101 | #define SVC_READLINKAT 78 // 0x4e 102 | #define SVC_FSTATAT 79 // 0x4f 103 | 104 | -------------------------------------------------------------------------------- /cmpt-fireyer/src/main/jni/inc/assembly.h: -------------------------------------------------------------------------------- 1 | #if defined(__aarch64__) 2 | #include "assembly-arm64.h" 3 | #elif defined(__arm__) 4 | #include "assembly-arm.h" 5 | #endif 6 | -------------------------------------------------------------------------------- /cmpt-fireyer/src/main/jni/inc/fireyer_native.h: -------------------------------------------------------------------------------- 1 | #ifndef __FIREYER_NATIVE_H__ 2 | #define __FIREYER_NATIVE_H__ 3 | 4 | #include 5 | 6 | enum { 7 | TYPE_GET_THREAD = 1, 8 | TYPE_GET_PROC = 2, 9 | TYPE_FILE_LIST = 3, 10 | TYPE_GET_STACK = 4, 11 | TYPE_GET_PROP_POPEN = 5, 12 | TYPE_GET_PROP_SPG = 6, 13 | TYPE_GET_PROP_SPRC = 7, 14 | }; 15 | 16 | class FireyerNative { 17 | public: 18 | static int svc_open(JNIEnv* env, jclass thiz, jstring jname, jboolean jmode); 19 | static int svc_read(JNIEnv* env, jclass thiz, jint fd, jbyteArray buffer, int bufferSize); 20 | static int svc_write(JNIEnv* env, jclass thiz, jint fd, jbyteArray buffer, int bufferSize); 21 | static int svc_close(JNIEnv* env, jclass thiz, jint fd); 22 | static jobjectArray svc_stat(JNIEnv* env, jclass thiz, jstring jname); 23 | static jstring svc_readlink(JNIEnv* env, jclass thiz, jint fd); 24 | 25 | static jobject handeJavaCall(JNIEnv* env, jclass thiz, jint jtype, jobject jobj); 26 | }; 27 | 28 | #endif// end of __FIREYER_NATIVE_H__ 29 | -------------------------------------------------------------------------------- /cmpt-fireyer/src/main/jni/src/fireyer_main.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | #include "fireyer_native.h" 3 | 4 | #ifndef NELEM 5 | # define NELEM(x) ((int) (sizeof(x) / sizeof((x)[0]))) 6 | #endif 7 | 8 | // ------------------------------------------------------------------------------------------------------------------------------------------------------ 9 | jint JNI_OnLoad(JavaVM *vm, void *reserved) { 10 | if (NULL == vm) { 11 | return -1; 12 | } 13 | 14 | /* Check GetEnv return value */ 15 | JNIEnv *env = NULL; 16 | JNIEnv **ppenv = &env; 17 | int ret = vm->GetEnv((void **) ppenv, JNI_VERSION_1_6); 18 | if (ret != JNI_OK) { 19 | return -2; 20 | } 21 | 22 | if (NULL == env) { 23 | return -3; 24 | } 25 | 26 | jclass clazz = env->FindClass("com/ifma/cmpt/fireyer/FireyerNative"); 27 | if (NULL == clazz) { 28 | return -4; 29 | } 30 | 31 | JNINativeMethod methods[] = { 32 | {"svc_open", "(Ljava/lang/String;Z)I", (void *) FireyerNative::svc_open}, 33 | {"svc_read", "(I[BI)I", (void *) FireyerNative::svc_read}, 34 | {"svc_write", "(I[BI)I", (void *) FireyerNative::svc_write}, 35 | {"svc_close", "(I)I", (void *) FireyerNative::svc_close}, 36 | {"svc_stat", "(Ljava/lang/String;)[Ljava/lang/Object;", (void *) FireyerNative::svc_stat}, 37 | {"svc_readlink", "(I)Ljava/lang/String;", (void *) FireyerNative::svc_readlink}, 38 | {"callNative", "(ILjava/lang/Object;)Ljava/lang/Object;", (void *) FireyerNative::handeJavaCall}, 39 | }; 40 | ret = env->RegisterNatives(clazz, methods, NELEM(methods)); 41 | if (ret < 0) { 42 | return -5; 43 | } 44 | 45 | return JNI_VERSION_1_6; 46 | } -------------------------------------------------------------------------------- /cmpt-fireyer/src/main/mk.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -u 3 | set -e 4 | 5 | LOCAL_PATH=`pwd` 6 | OUT_PATH=$1 7 | BUILD_TYPE=$2 8 | 9 | # ------------------------------------------------------------------------------------------------------ 10 | ndk-build -C jni clean 11 | if [ $BUILD_TYPE = 'debug' ] ; then 12 | ndk-build -C jni NDK_DEBUG=1 13 | else 14 | ndk-build -C jni 15 | fi 16 | 17 | # ------------------------------------------------------------------------------------------------------ 18 | # ------------------------------------------------------------------------------------------------------ 19 | #rm -rf ${OUT_PATH}/libs 20 | #mv libs ${OUT_PATH} 21 | 22 | # ------------------------------------------------------------------------------------------------------ 23 | rm -rf obj 24 | #rm -rf libs 25 | -------------------------------------------------------------------------------- /cocollider.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | # @Brief: mk 4 | # @Date: 2024.11.08 16:52:52 5 | 6 | import sys, os, re, time 7 | from datetime import datetime 8 | 9 | g_env_path = os.getcwd() 10 | g_this_file = os.path.realpath(sys.argv[0]) 11 | g_this_path = os.path.dirname(g_this_file) 12 | 13 | COCO_TYPE_CLASS = 10 14 | COCO_TYPE_NATIVE = 20 15 | 16 | COCO_TYPE_CLASS_NAME = 0 17 | COCO_TYPE_CLASS_METHOD = 1 18 | COCO_TYPE_CLASS_FIELD = 2 19 | COCO_TYPE_NATIVE_METHOD = 3 20 | COCO_TYPE_NATIVE_FIELD = 4 21 | 22 | COCO_KEY = '@CoCollider' 23 | COCO_KEY_LENGTH = len(COCO_KEY) 24 | 25 | TARGET_PACKAGE = "com.ifma.cmpt.demo.fireyer" 26 | 27 | g_target_file_types = ['.h','.inl','.cpp','.c','.java','.kt','.aidl'] 28 | # -------------------------------------------------------------------------------------------------------------------------- 29 | # init project env 30 | g_wing_path = os.path.expanduser("~") + os.sep + '.wing/wing' # such as: /Users/${username}/.wing/wing 31 | sys.path.append(g_wing_path) 32 | from utils.utils_import import ImportUtils 33 | g_space_path = ImportUtils.initSpaceEnv(g_env_path) 34 | 35 | from utils.utils_file import FileUtils 36 | from utils.utils_adb import AdbUtils 37 | from utils.utils_logger import LoggerUtils 38 | # -------------------------------------------------------------------------------------------------------------------------- 39 | class CocoMember:# fields ande methods 40 | 41 | def __init__(self, _name, _typ): 42 | self.name = _name 43 | self.typ = _typ 44 | self.lines = [] 45 | 46 | def addLine(self, _fname, _lineNum): 47 | self.lines.append(_fname + (',%d' % _lineNum)) 48 | 49 | def println(self, writer): 50 | # + method name 51 | # > /home/demo.java,124 52 | # - field name 53 | # > /home/demo.java,124 54 | if self.typ == COCO_TYPE_NATIVE_METHOD or self.typ == COCO_TYPE_CLASS_METHOD: 55 | writer.write('+ ' + self.name + '\n') 56 | elif self.typ == COCO_TYPE_CLASS_FIELD: 57 | writer.write('- ' + self.name + '\n') 58 | elif self.typ == COCO_TYPE_CLASS: 59 | writer.write('= ' + self.name + '\n') 60 | elif self.typ == COCO_TYPE_NATIVE: 61 | writer.write('~ ' + self.name + '\n') 62 | else: 63 | assert 0, 'Unknown type: %d' % self.typ 64 | # self.lines = sorted(self.lines) 65 | self.lines.sort() 66 | for line in self.lines: 67 | writer.write('> ' + line + '\n') 68 | writer.write('\n') 69 | 70 | 71 | class CocoClass: 72 | def __init__(self, _name, _typ): 73 | self.members = {} 74 | self.members[' '] = CocoMember(_name, _typ) 75 | 76 | def addClass(self, _fname, _lineNum):# only for class or lib name 77 | item = self.members.get(' ') 78 | item.addLine(_fname, _lineNum) 79 | 80 | def addItem(self, _fname, _lineNum, _member, _memberType): 81 | item = self.members.get(_member) 82 | if item is None: 83 | item = CocoMember(_member, _memberType) 84 | self.members[_member] = item 85 | item.addLine(_fname, _lineNum) 86 | 87 | def println(self, writer): 88 | keys = list(self.members.keys()) 89 | keys.sort() 90 | for key in keys: self.members[key].println(writer) 91 | writer.write('\n') 92 | 93 | 94 | class CocoGroup: 95 | def __init__(self): 96 | self.classes = {} 97 | 98 | def addClass(self, _fname, _lineNum, _cname, _ctype): 99 | cls = self.classes.get(_cname) 100 | if cls is None: 101 | cls = CocoClass(_cname, _ctype) 102 | self.classes[_cname] = cls 103 | cls.addClass(_fname, _lineNum) 104 | 105 | def addItem(self, _fname, _lineNum, _cname, _ctype, _mname, _mtype): 106 | cls = self.classes.get(_cname) 107 | if cls is None: 108 | cls = CocoClass(_cname, _ctype) 109 | self.classes[_cname] = cls 110 | cls.addItem(_fname, _lineNum, _mname, _mtype) 111 | 112 | def println(self, writer): 113 | keys = list(self.classes.keys()) 114 | keys.sort() 115 | 116 | for key in keys: 117 | print('> ' + key) 118 | writer.write('############################################################\n') 119 | self.classes[key].println(writer) 120 | writer.write('\n') 121 | print('\n%d targets found.' % len(keys)) 122 | 123 | 124 | def getMatch(index, matches, isClass): 125 | while index < len(matches): 126 | item = matches[index].strip() 127 | index += 1 128 | if len(item) <= 0: continue 129 | if isClass and item.find('.') < 0: continue 130 | return index, item 131 | return index, None 132 | 133 | def doParseLine(group, line, fname, lineNum): 134 | # @CoCollider android.utils.Abc,-mFile 135 | # @CoCollider android.utils.Abc,-mFile,mName 136 | # @CoCollider android/utils/Abc,-mFile 137 | # @CoCollider android.utils.Abc,+getFile,-mName 138 | # @CoCollider android/utils/Abc,+getFile,+getName,-mName 139 | # Class.forName("android.utils.Abc");// @CoCollider 140 | # ReflectUtils.getStaticField("android.utils.Abc", "mName");// @CoCollider ,- 141 | # @CoCollider ~libc.so,+open 142 | # @CoCollider ~/system/lib/libc.so,+open 143 | # @CoCollider ~/system/lib/libc.so,+open,+close 144 | # utils_dlsym("libc.so", "open");// @CoCollider ~,+ 145 | # utils_dlsym("open");// @CoCollider ~libc.so,+ 146 | pos = line.find(COCO_KEY) 147 | if pos < 0: return 148 | fmt = line[pos + COCO_KEY_LENGTH:].strip() 149 | items = fmt.split(',') 150 | matches = re.findall(r'"(.*?)"', line[:pos]) 151 | 152 | i, j = 1, 0 153 | cname = items[0] 154 | ctype = COCO_TYPE_CLASS 155 | if len(cname) <= 0: 156 | j, cname = getMatch(j, matches, True) 157 | if len(cname) <= 0: return 158 | if cname.startswith('~'): 159 | cname = cname[1:] 160 | ctype = COCO_TYPE_NATIVE 161 | if len(cname) <= 0: 162 | j, cname = getMatch(j, matches, False) 163 | assert cname is not None, "Invalid member: " + line 164 | elif cname.startswith('='): 165 | cname = cname[1:] 166 | ctype = COCO_TYPE_CLASS 167 | if len(cname) <= 0: 168 | j, cname = getMatch(j, matches, True) 169 | assert cname is not None, "Invalid member: " + line 170 | if ctype == COCO_TYPE_CLASS: 171 | cname = cname.replace('/', '.') 172 | cname = cname.replace('\\', '.') 173 | 174 | l = len(items) 175 | if l <= i: 176 | group.addClass(fname, lineNum, cname, ctype) 177 | return 178 | 179 | gotItem = False 180 | while i < l: 181 | item = items[i].strip() 182 | i += 1 183 | if len(item) <= 0: continue 184 | if item.startswith('-'): 185 | if '-' == item: 186 | j, item = getMatch(j, matches, False) 187 | assert item is not None, "Invalid member: " + line 188 | else: 189 | item = item[1:].strip() 190 | gotItem = True 191 | group.addItem(fname, lineNum, cname, ctype, item, COCO_TYPE_CLASS_FIELD if ctype == COCO_TYPE_CLASS else COCO_TYPE_NATIVE_FIELD) 192 | elif item.startswith('+'): 193 | if '+' == item: 194 | j, item = getMatch(j, matches, False) 195 | assert item is not None, "Invalid member: " + line 196 | else: 197 | item = item[1:].strip() 198 | gotItem = True 199 | group.addItem(fname, lineNum, cname, ctype, item, COCO_TYPE_CLASS_METHOD if ctype == COCO_TYPE_CLASS else COCO_TYPE_NATIVE_METHOD) 200 | else: 201 | assert 0, 'unknown: ' + line 202 | if not gotItem: print('Warn: ' + line) 203 | 204 | 205 | def isTargetFile(f): 206 | pos = f.rfind('.') 207 | return 0 < pos and f[pos:] in g_target_file_types 208 | 209 | 210 | def doScan(path, group): 211 | print('do scan ...') 212 | l = len(path) 213 | minLen = COCO_KEY_LENGTH + 2 214 | for root, dirs, files in os.walk(path): 215 | for name in files: 216 | if not isTargetFile(name): continue 217 | fileName = os.path.join(root, name) 218 | fname = fileName[l+1:] 219 | lineNum = 0 220 | with open(fileName, 'r') as f: 221 | while True: 222 | line = f.readline() 223 | if None == line or len(line) <= 0: break 224 | lineNum += 1 225 | line = line.strip() 226 | if len(line) < minLen: continue 227 | doParseLine(group, line, fname, lineNum) 228 | 229 | 230 | def doPrintln(path, group): 231 | # cocollider-20241023-112044.txt 232 | if not os.path.isdir(path): os.makedirs(path) 233 | 234 | now = datetime.now() 235 | fname = now.strftime('cocollider-scan-%Y%m%d-%H%M%S.txt') 236 | fileName = path + os.sep + fname 237 | with open(fileName, 'w') as f: 238 | group.println(f) 239 | print('>>> ' + fileName) 240 | 241 | 242 | def doCall(extras): 243 | LoggerUtils.println("call provider: " + TARGET_PACKAGE) 244 | AdbUtils.launchApp(TARGET_PACKAGE) 245 | ret = AdbUtils.callProvider(TARGET_PACKAGE + ".MainProvider", 246 | "coco", 247 | "coco", 248 | extras 249 | ) 250 | LoggerUtils.println(ret) 251 | return ret 252 | 253 | 254 | def doRunner(inFile, outPath): 255 | if not os.path.isfile(inFile): 256 | LoggerUtils.e("Invalid scan file") 257 | return 258 | targetFile = "/data/local/tmp/cocollider-scan.txt" 259 | runOutFile = "/sdcard/Android/data/" + TARGET_PACKAGE + "/cocollider-run.txt" 260 | AdbUtils.doAdbCmd('shell rm -f ' + targetFile) 261 | AdbUtils.doAdbCmd('shell rm -f ' + runOutFile) 262 | AdbUtils.push(inFile, targetFile) 263 | extras = { 264 | "key-in" : targetFile 265 | } 266 | ret = doCall(extras) 267 | LoggerUtils.println(ret) 268 | 269 | LoggerUtils.println('waiting ...') 270 | 271 | now = datetime.now() 272 | fname = now.strftime('cocollider-run-%Y%m%d-%H%M%S.txt') 273 | outFile = outPath + "/" + fname 274 | 275 | cnt = 0 276 | while cnt < 3: 277 | cnt += 1 278 | time.sleep(1) 279 | AdbUtils.pull(runOutFile, outFile) 280 | if os.path.isfile(outFile): 281 | LoggerUtils.println('> ' + outFile) 282 | LoggerUtils.light('success') 283 | return 284 | LoggerUtils.w('CoCollider run fail') 285 | 286 | 287 | def run(): 288 | # ./cocollider.py scan 289 | # ./cocollider.py scan ${path} 290 | # ./cocollider.py run ${file} 291 | if len(sys.argv) < 2: 292 | print('Invalid args.') 293 | print(' ./cocollider.py scan') 294 | print(' ./cocollider.py scan ${path}') 295 | print(' ./cocollider.py run ${file}') 296 | return 297 | 298 | cmd = sys.argv[1] 299 | if cmd == 'scan': 300 | group = CocoGroup() 301 | path = sys.argv[2] if 2 < len(sys.argv) else g_env_path 302 | doScan(path, group) 303 | doPrintln(g_env_path, group) 304 | print('done.') 305 | return 306 | if cmd == 'run': 307 | doRunner(sys.argv[2], g_env_path) 308 | else: 309 | print('Invalid cmd: ' + cmd) 310 | 311 | 312 | if __name__ == "__main__": 313 | run() -------------------------------------------------------------------------------- /files/default.gradle: -------------------------------------------------------------------------------- 1 | allprojects { 2 | repositories { 3 | maven { url 'https://maven.aliyun.com/repository/public' } 4 | maven { url 'https://maven.aliyun.com/repository/google' } 5 | maven { url 'https://www.jitpack.io' } 6 | } 7 | } 8 | 9 | ext { 10 | androidBuildToolsVersion = "30.0.3" 11 | androidCompileSdkVersion = 30 12 | androidVersionCode = 1 13 | androidVersionName = "1.0" 14 | androidMinSdkVersion = 29// 10.0 15 | androidTargetSdkVersion = 30// 11.0 16 | testInstrumentationRunner = "android.support.test.runner.AndroidJUnitRunner" 17 | } 18 | -------------------------------------------------------------------------------- /files/fireyer.keystore: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iofomo/fireyer/05b26b41c381a198ddfd7a6f9fa2d6ec694be9f1/files/fireyer.keystore -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | ## Project-wide Gradle settings. 2 | # 3 | # For more details on how to configure your build environment visit 4 | # http://www.gradle.org/docs/current/userguide/build_environment.html 5 | # 6 | # Specifies the JVM arguments used for the daemon process. 7 | # The setting is particularly useful for tweaking memory settings. 8 | # Default value: -Xmx1024m -XX:MaxPermSize=256m 9 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 10 | # 11 | # When configured, Gradle will run in incubating parallel mode. 12 | # This option should only be used with decoupled projects. More details, visit 13 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 14 | # org.gradle.parallel=true 15 | #Fri Oct 21 11:03:45 CST 2016 16 | #systemProp.https.proxyPort=8888 17 | #systemProp.http.proxyHost=192.168.1.100 18 | #不使用代理,正常情况下,Maven库都可以直接访问 19 | systemProp.http.nonProxyHosts=* 20 | org.gradle.jvmargs=-Xmx1536m 21 | android.injected.testOnly=false 22 | android.useAndroidX=true 23 | android.enableJetifier=true 24 | #android.useAndroidX=true 25 | ## Automatically convert third-party libraries to use AndroidX 26 | #android.enableJetifier=true 27 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iofomo/fireyer/05b26b41c381a198ddfd7a6f9fa2d6ec694be9f1/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Thu Sep 10 15:56:22 CST 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.9.2-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Attempt to set APP_HOME 10 | # Resolve links: $0 may be a link 11 | PRG="$0" 12 | # Need this for relative symlinks. 13 | while [ -h "$PRG" ] ; do 14 | ls=`ls -ld "$PRG"` 15 | link=`expr "$ls" : '.*-> \(.*\)$'` 16 | if expr "$link" : '/.*' > /dev/null; then 17 | PRG="$link" 18 | else 19 | PRG=`dirname "$PRG"`"/$link" 20 | fi 21 | done 22 | SAVED="`pwd`" 23 | cd "`dirname \"$PRG\"`/" >/dev/null 24 | APP_HOME="`pwd -P`" 25 | cd "$SAVED" >/dev/null 26 | 27 | APP_NAME="Gradle" 28 | APP_BASE_NAME=`basename "$0"` 29 | 30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 31 | DEFAULT_JVM_OPTS="" 32 | 33 | # Use the maximum available, or set MAX_FD != -1 to use that value. 34 | MAX_FD="maximum" 35 | 36 | warn () { 37 | echo "$*" 38 | } 39 | 40 | die () { 41 | echo 42 | echo "$*" 43 | echo 44 | exit 1 45 | } 46 | 47 | # OS specific support (must be 'true' or 'false'). 48 | cygwin=false 49 | msys=false 50 | darwin=false 51 | nonstop=false 52 | case "`uname`" in 53 | CYGWIN* ) 54 | cygwin=true 55 | ;; 56 | Darwin* ) 57 | darwin=true 58 | ;; 59 | MINGW* ) 60 | msys=true 61 | ;; 62 | NONSTOP* ) 63 | nonstop=true 64 | ;; 65 | esac 66 | 67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 68 | 69 | # Determine the Java command to use to start the JVM. 70 | if [ -n "$JAVA_HOME" ] ; then 71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 72 | # IBM's JDK on AIX uses strange locations for the executables 73 | JAVACMD="$JAVA_HOME/jre/sh/java" 74 | else 75 | JAVACMD="$JAVA_HOME/bin/java" 76 | fi 77 | if [ ! -x "$JAVACMD" ] ; then 78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 79 | 80 | Please set the JAVA_HOME variable in your environment to match the 81 | location of your Java installation." 82 | fi 83 | else 84 | JAVACMD="java" 85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 86 | 87 | Please set the JAVA_HOME variable in your environment to match the 88 | location of your Java installation." 89 | fi 90 | 91 | # Increase the maximum file descriptors if we can. 92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then 93 | MAX_FD_LIMIT=`ulimit -H -n` 94 | if [ $? -eq 0 ] ; then 95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 96 | MAX_FD="$MAX_FD_LIMIT" 97 | fi 98 | ulimit -n $MAX_FD 99 | if [ $? -ne 0 ] ; then 100 | warn "Could not set maximum file descriptor limit: $MAX_FD" 101 | fi 102 | else 103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 104 | fi 105 | fi 106 | 107 | # For Darwin, add options to specify how the application appears in the dock 108 | if $darwin; then 109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 110 | fi 111 | 112 | # For Cygwin, switch paths to Windows format before running java 113 | if $cygwin ; then 114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 116 | JAVACMD=`cygpath --unix "$JAVACMD"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Escape application args 158 | save () { 159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done 160 | echo " " 161 | } 162 | APP_ARGS=$(save "$@") 163 | 164 | # Collect all arguments for the java command, following the shell quoting and substitution rules 165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS" 166 | 167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong 168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then 169 | cd "$(dirname "$0")" 170 | fi 171 | 172 | exec "$JAVACMD" "$@" 173 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /img/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iofomo/fireyer/05b26b41c381a198ddfd7a6f9fa2d6ec694be9f1/img/1.png -------------------------------------------------------------------------------- /img/fireyer.svg: -------------------------------------------------------------------------------- 1 | 2 | Android: 9.x ~ 14.x 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | Android 16 | 9 . x ~ 1 4 . x 17 | 18 | -------------------------------------------------------------------------------- /img/thanks.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/iofomo/fireyer/05b26b41c381a198ddfd7a6f9fa2d6ec694be9f1/img/thanks.png -------------------------------------------------------------------------------- /mk.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding:utf-8 -*- 3 | # @Brief: mk 4 | # @Date: 2024.01.08 16:52:52 5 | 6 | import sys, os 7 | 8 | g_env_path = os.getcwd() 9 | g_this_file = os.path.realpath(sys.argv[0]) 10 | g_this_path = os.path.dirname(g_this_file) 11 | # -------------------------------------------------------------------------------------------------------------------------- 12 | # init project env 13 | g_wing_path = os.path.expanduser("~") + os.sep + '.wing/wing' # such as: /Users/${username}/.wing/wing 14 | sys.path.append(g_wing_path) 15 | from utils.utils_import import ImportUtils 16 | g_space_path = ImportUtils.initSpaceEnv(g_env_path) 17 | 18 | from utils.utils_cmn import CmnUtils 19 | from utils.utils_zip import ZipUtils 20 | from utils.utils_file import FileUtils 21 | from utils.utils_logger import LoggerUtils 22 | from basic.arguments import BasicArgumentsValue 23 | # -------------------------------------------------------------------------------------------------------------------------- 24 | 25 | 26 | def getModules(): 27 | if False: 28 | # 你也可以在这里定制要编译模块和顺序 29 | return [ 30 | "cmpt-fireyer", 31 | # add more module here ... 32 | "app", 33 | ] 34 | 35 | # 默认编译所有项,且jni模块第一个编译,app模块最后一个编译 36 | modules = [] 37 | hasJni, hasApp = False, False 38 | for item in os.listdir(g_this_path): 39 | if not os.path.isdir(g_this_path + os.sep + item): continue 40 | if not os.path.isfile(g_this_path + os.sep + item + '/mk.sh'): continue 41 | if 'jni' == item: hasJni = True 42 | elif 'app' == item: hasApp = True 43 | else: modules.append(item) 44 | if hasJni: modules.insert(0, 'jni') 45 | if hasApp: modules.append('app') 46 | return modules 47 | 48 | 49 | def buildModules(OUT_PATH, BUILD_TYPE, modules): 50 | OUT_PATH += os.sep + BUILD_TYPE 51 | FileUtils.remove(OUT_PATH) 52 | FileUtils.ensureDir(OUT_PATH) 53 | for module in modules: buildModule(OUT_PATH, BUILD_TYPE, module) 54 | 55 | 56 | def buildModule(OUT_PATH, BUILD_TYPE, module): 57 | modulePath = g_this_path + os.sep + module 58 | if not os.path.exists(modulePath): return 59 | LoggerUtils.println('Build ' + module) 60 | if 'jni' != module:# aar module build 61 | ret = CmnUtils.doCmdCall('cd %s && ./mk.sh %s %s %s' % (modulePath, OUT_PATH, BUILD_TYPE, module)) 62 | else:# native module build 63 | OUT_JNI_PATH = g_space_path + '/out/jni/' + BUILD_TYPE 64 | FileUtils.ensureDir(OUT_JNI_PATH + '/armeabi-v7a/') 65 | FileUtils.ensureDir(OUT_JNI_PATH + '/arm64-v8a/') 66 | FileUtils.ensureDir(OUT_JNI_PATH + '/x86/') 67 | FileUtils.ensureDir(OUT_JNI_PATH + '/x86_64/') 68 | ret = CmnUtils.doCmdCall('cd %s && ./mk.sh %s %s %s %s' % (modulePath, OUT_PATH, OUT_JNI_PATH, BUILD_TYPE, module)) 69 | assert ret, 'Error: build fail ' + module 70 | 71 | 72 | def ensureEnv(): 73 | local = g_this_path + '/local.properties' 74 | if os.path.isfile(local): return 75 | header = [ 76 | '## This file must *NOT* be checked into Version Control Systems,\n' 77 | '# as it contains information specific to your local configuration.\n', 78 | '#\n', 79 | '# Location of the SDK. This is only used by Gradle.\n', 80 | '# For customization when using a Version Control System, please read the\n', 81 | '# header note.\n', 82 | '#Wed Oct 28 18:13:44 CST 2023\n' 83 | ] 84 | with open(local, 'w') as f: f.writelines(header) 85 | 86 | 87 | def run(): 88 | zarg = BasicArgumentsValue() 89 | if 2 <= zarg.count(): 90 | OUT_PATH, BUILD_TYPE, MODULE = zarg.get(0), zarg.get(1), zarg.get(2) 91 | else: # build from local 92 | BUILD_TYPE = 'debug' 93 | OUT_PATH = g_space_path + '/out' + g_this_path[len(g_space_path):] 94 | MODULE = None 95 | try: 96 | ensureEnv() 97 | if os.path.exists(g_this_path + '/gradlew'): 98 | ret = CmnUtils.doCmdCall('cd %s && ./gradlew clean' % (g_this_path)) 99 | assert ret, 'Error: gradlew clean' 100 | 101 | modules = getModules() 102 | assert CmnUtils.isEmpty(MODULE) or MODULE in modules, 'Not found: ' + MODULE 103 | 104 | if BUILD_TYPE == 'all': 105 | if CmnUtils.isEmpty(MODULE): 106 | buildModules(OUT_PATH, 'debug', modules) 107 | buildModules(OUT_PATH, 'release', modules) 108 | else: 109 | buildModule(OUT_PATH, 'debug', MODULE) 110 | buildModule(OUT_PATH, 'release', MODULE) 111 | elif CmnUtils.isEmpty(MODULE): 112 | buildModules(OUT_PATH, BUILD_TYPE, modules) 113 | else: 114 | buildModule(OUT_PATH, BUILD_TYPE, MODULE) 115 | except Exception as e: 116 | LoggerUtils.println(e) 117 | raise SyntaxError(e) 118 | 119 | 120 | if __name__ == "__main__": 121 | run() 122 | -------------------------------------------------------------------------------- /proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | 19 | -keep class android.support.** { *; } 20 | -keep class butterknife.** {*;} 21 | -keep class **.R$* 22 | 23 | -keep class * implements android.os.Parcelable { 24 | static ** CREATOR; 25 | } 26 | 27 | -dontshrink 28 | -dontoptimize 29 | -dontpreverify 30 | -dontwarn 31 | -ignorewarnings 32 | 33 | -keeppackagenames android.app.ifma.* 34 | 35 | -keep class * implements android.app.ifma.cmpt.utils.ProguardKeeper { 36 | public *; 37 | } 38 | 39 | -keep class * implements com.ifma.cmpt.utils.ProguardKeeper { 40 | public *; 41 | } 42 | 43 | -keepclasseswithmembernames class * { 44 | native ; 45 | } -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | include ':cmpt-fireyer' 3 | include ':cmpt-cocollider' 4 | --------------------------------------------------------------------------------