【问题标题】:Running binary files运行二进制文件
【发布时间】:2021-04-04 01:22:18
【问题描述】:

我能够从 Internet 下载二进制文件并以编程方式将其保存在我的 Android 设备上,问题是选择能够执行它的正确位置,我选择了 app internaldata directory 但两者都给了我:

无法运行程序“/data/user/0/com.example.dl/app_mounted/server”: 错误=13,权限被拒绝

我的代码是: MainActivity.kt

package com.example.dl

import android.content.Context
import android.content.ContextWrapper
import android.net.Uri
import android.os.Bundle
import android.os.Environment
import android.util.Log
import android.view.View
import androidx.appcompat.app.AppCompatActivity
import androidx.lifecycle.lifecycleScope
import com.example.dl.databinding.ActivityMainBinding
import kotlinx.coroutines.*
import java.io.*
import java.lang.RuntimeException
import java.net.URL
import java.util.*


class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)
        val context = this
       val urlFile:URL = URL("https://drive.google.com/uc?export=download&id=" +
                "1kRtYw3_Yd7he0HjbgNlAAl9we9tQEGvm")

        binding.tvDownload.text = urlFile.toString()
        val tag = "Main Activity"
        val targetFileName = "server"

        val wrapper = ContextWrapper(context)
        /* ******************************** */
        /** What Directory Should I Select **/
        var directory = wrapper.getDir("${Environment.getExternalStorageState()}", Context.MODE_PRIVATE)
        /* ******************************** */
        var file = File(directory, targetFileName)

        binding.button.setOnClickListener { button ->
            lifecycleScope.launch {
                if (file.exists()) {
                    Log.i(tag, "$file does exist.")
                    // Runtime.getRuntime().exec("/system/bin/rm /$file")

                    Log.i(tag, "Setting file executable")
                    file?.setExecutable(true)
                    Log.i(tag, "Running executable file")
                    Runtime.getRuntime().exec(file.toString())

                    //   Runtime.getRuntime().exec("/bin/sh -c $file")

                    binding.tvSaved.text = file.toString()

                    button.isEnabled = true // enable button
                    binding.progressBar.visibility = View.INVISIBLE
                } else {
                    Log.i(tag, "$file does not exist.")
                    binding.tvSaved.text = ""

                button.isEnabled = false // disable button
                binding.progressBar.visibility = View.VISIBLE

                // perform these tasks off the main thread
                val savedUri: Uri? = withContext(Dispatchers.IO) {
                    // get / download bitmap from url
                    val fileStream: InputStream? = urlFile.toStream(context)
                    Log.i(
                        tag,
                        "Stream $fileStream collected, trying to save it"
                    ) 
                    fileStream?.saveToInternalStorage(context)
                }

                if (savedUri == null) {
                    Log.e(tag, "URI was null. Nothing to save")
                    return@launch
                }

                val execFile = File(savedUri.toString())
                Log.i(tag, "Stream saved")

                Log.i(tag, "Setting file executable")
                execFile?.setExecutable(true)
                Log.i(tag, "Running executable file")
                Runtime.getRuntime().exec(savedUri.toString())

                //   Runtime.getRuntime().exec("/bin/sh -c $savedUri")

                // show bitmap saved uri in text view
                binding.tvSaved.text = savedUri.toString()

                button.isEnabled = true // enable button
                binding.progressBar.visibility = View.INVISIBLE
            }

            }
        }
}

Download.kt

package com.example.dl

import android.content.Context
import android.util.Log
import java.io.*
import java.net.HttpURLConnection
import java.net.URL

// extension function to get / download bitmap from url
fun URL.toStream(context : Context): InputStream? {
    return try {
        val tag = "input stream"
            Log.v(tag, "downloadFile() invoked ")
            Log.v(tag, "downloadFile() fileUrl $this")
        //    Log.v(TAG, "downloadFile() directory $directory")
            val url = URL(this.toString())
            val urlConnection = url.openConnection() as HttpURLConnection
            urlConnection.connect()
            val inputStream = urlConnection.inputStream
        inputStream
    } catch (e: IOException){
        null
    }
}

SaveToInternal.kt

package com.example.dl

import android.content.ContentValues
import android.content.Context
import android.content.ContextWrapper
import android.net.Uri
import android.os.Environment
import android.util.Log
import java.io.*
import java.net.MalformedURLException

// extension function to save an image to internal storage
fun InputStream.saveToInternalStorage(context: Context): Uri?{
    return try {
        val tag = "Saving stream"
        Log.i(tag, "Saving the stream from the web")
        val MEGABYTE = 1024 * 1024
        val buffer = ByteArray(MEGABYTE)
        val targetFileName = "server"
        val wrapper = ContextWrapper(context)
         /* ******************************** */
        /** What Directory Should I Select **/
        var directory = wrapper.getDir("${Environment.getExternalStorageState()}", Context.MODE_PRIVATE)
        /* ******************************** */
        // create a file to save the downloaded one
        var file = File(directory, targetFileName)
        // get the file output stream
        val fileOutputStream: OutputStream = FileOutputStream(file)

        var bufferLength = 0
        while (this.read(buffer).also { bufferLength = it } > 0) {
            fileOutputStream.write(buffer, 0, bufferLength)
        }
        fileOutputStream.flush()
        fileOutputStream.close()
        Log.v(tag, "downloadFile() completed ${Uri.parse(file.absolutePath)}")
        Uri.parse(file.absolutePath)
    } catch (e: FileNotFoundException) {
        e.printStackTrace()
        Log.e(ContentValues.TAG, "downloadFile() error" + e.message)
        Log.e(ContentValues.TAG, "downloadFile() error" + e.stackTrace)
        null
    } catch (e: MalformedURLException) {
        e.printStackTrace()
        Log.e(ContentValues.TAG, "downloadFile() error" + e.message)
        Log.e(ContentValues.TAG, "downloadFile() error" + e.stackTrace)
        null
    } catch (e: IOException) {
        e.printStackTrace()
        Log.e(ContentValues.TAG, "downloadFile() error" + e.message)
        Log.e(ContentValues.TAG, "downloadFile() error" + e.stackTrace)
        null
    }
}

layout/activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#EDEAE0"
    tools:context=".MainActivity"
    tools:viewBindingIgnore="false">

    <com.google.android.material.button.MaterialButton
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:backgroundTint="#7BB661"
        android:text="Download Image"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <ProgressBar
        android:id="@+id/progressBar"
        style="?android:attr/progressBarStyle"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:visibility="invisible"
        app:layout_constraintBottom_toBottomOf="@+id/button"
        app:layout_constraintStart_toEndOf="@+id/button"
        app:layout_constraintTop_toTopOf="@+id/button" />

    <ImageView
        android:id="@+id/imageView"
        android:layout_width="0dp"
        android:layout_height="350dp"
        android:layout_marginStart="8dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="8dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="1.0"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/tvDownload"
        tools:srcCompat="@tools:sample/avatars" />

    <TextView
        android:id="@+id/tvDownload"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        tools:text="Download URL"
        style="@style/TextAppearance.MaterialComponents.Subtitle2"
        android:padding="8dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/button" />

    <com.google.android.material.textview.MaterialTextView
        android:id="@+id/tvSaved"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginTop="8dp"
        tools:text="Saved Uri"
        android:padding="8dp"
        style="@style/TextAppearance.MaterialComponents.Subtitle1"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/imageView" />

</androidx.constraintlayout.widget.ConstraintLayout>

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.dl">
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Dl">
        <activity android:name=".MainActivity">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

build.gradle (Module)

plugins {
    id 'com.android.application'
    id 'kotlin-android'
    id 'kotlin-parcelize'
}

android {
    compileSdkVersion 30
    buildToolsVersion "30.0.3"

    defaultConfig {
        applicationId "com.example.dl"
        minSdkVersion 30
        targetSdkVersion 30
        versionCode 1
        versionName "1.0"

        testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
    }

    buildFeatures {
        dataBinding true
        viewBinding true
    }

    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
        }
    }
    compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
    kotlinOptions {
        jvmTarget = '1.8'
    }
}

dependencies {
    implementation 'com.android.volley:volley:1.2.0'
    // kotlin coroutine
    implementation "androidx.lifecycle:lifecycle-runtime-ktx:2.3.1"
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-core:1.3.8'
    implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.3.8'

    implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
    implementation 'androidx.core:core-ktx:1.3.2'
    implementation 'androidx.appcompat:appcompat:1.2.0'
    implementation 'com.google.android.material:material:1.3.0'
    implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
    testImplementation 'junit:junit:4.+'
    androidTestImplementation 'androidx.test.ext:junit:1.1.2'
    androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}

更新 我看到下面是使用calling native libjniLibs 库的示例我如何使用executing native binary 我没有源代码

package com.example.dl

import android.os.Bundle
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity

open class MainActivity : AppCompatActivity() {
    companion object {
        init {
            System.loadLibrary("native-lib")
        }
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        // Example of a call to a native method
        val tv: TextView = findViewById(R.id.tvDownload)
        tv.text = stringFromJNI()
    }

    /**
     * A native method that is implemented by the 'native-lib' native library,
     * which is packaged with this application.
     */
    private external fun stringFromJNI(): String?
}

*.so 文件已通过相应平台(arm64-v8a、armeabi-v7a、x86、x86_64)文件夹推送:app/src/main/jniLibs/armeabi-v7a/native-lib.so

【问题讨论】:

    标签: android


    【解决方案1】:

    出于安全原因,现代版本的 Android 不支持此功能。引用the documentation:

    以 Android 10 为目标的不受信任的应用无法对应用主目录中的文件调用 exec()。来自可写应用主目录的文件执行是W^X violation。应用应仅加载嵌入在应用的 APK 文件中的二进制代码。

    请注意,您的行为也可能违反您所需应用分发渠道的服务条款。

    【讨论】:

    • 谢谢,如何获取它embedded within an app's APK file 并从那里执行它,我尝试在assets 中使用它,但知道它也无法执行。
    • @HasanAYousef:您可以使用 NDK 将本机代码编译到您的应用程序中。
    • 我没有源代码,只有最终的二进制文件,所以想运行它!
    猜你喜欢
    • 2012-08-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-26
    • 2015-09-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多