Merge "Fix fail verification without cleaning child session data"
This commit is contained in:
@@ -2112,6 +2112,11 @@ public class PackageInstallerSession extends IPackageInstallerSession.Stub {
|
||||
Slog.e(TAG, "Failed to verify session " + sessionId + " [" + msgWithErrorCode + "]");
|
||||
// Session is sealed and committed but could not be verified, we need to destroy it.
|
||||
destroyInternal();
|
||||
if (isMultiPackage()) {
|
||||
for (PackageInstallerSession childSession : getChildSessions()) {
|
||||
childSession.destroyInternal();
|
||||
}
|
||||
}
|
||||
if (isStaged()) {
|
||||
mStagedSession.setSessionFailed(
|
||||
SessionInfo.STAGED_SESSION_VERIFICATION_FAILED, msgWithErrorCode);
|
||||
|
||||
@@ -20,6 +20,13 @@
|
||||
|
||||
<target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
|
||||
|
||||
<target_preparer class="com.android.tradefed.targetprep.RunCommandTargetPreparer">
|
||||
<option name="run-command"
|
||||
value="pm uninstall com.android.cts.install.lib.testapp.A" />
|
||||
<option name="teardown-command"
|
||||
value="pm uninstall com.android.cts.install.lib.testapp.A" />
|
||||
</target_preparer>
|
||||
|
||||
<test class="com.android.tradefed.testtype.HostTest">
|
||||
<option name="jar" value="PackageManagerServiceHostTests.jar" />
|
||||
</test>
|
||||
|
||||
@@ -0,0 +1,55 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.pm.test
|
||||
|
||||
import com.android.tradefed.testtype.DeviceJUnit4ClassRunner
|
||||
import com.android.tradefed.testtype.junit4.BaseHostJUnit4Test
|
||||
import com.google.common.truth.Truth
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import org.junit.rules.TemporaryFolder
|
||||
import org.junit.runner.RunWith
|
||||
import kotlin.jvm.JvmField
|
||||
|
||||
@RunWith(DeviceJUnit4ClassRunner::class)
|
||||
class PackageInstallerSessionTest : BaseHostJUnit4Test() {
|
||||
companion object {
|
||||
private const val DEVICE_SIDE = "PackageManagerServiceDeviceSideTests.apk"
|
||||
}
|
||||
|
||||
@Rule
|
||||
@JvmField
|
||||
val tempFolder = TemporaryFolder()
|
||||
|
||||
@Test
|
||||
fun verify_parentSessionFail_childSessionFiles_shouldBeDestroyed() {
|
||||
runDeviceTest("com.android.server.pm.PackageInstallerSessionTest",
|
||||
"verify_parentSessionFail_childSessionFiles_shouldBeDestroyed")
|
||||
}
|
||||
|
||||
/**
|
||||
* Run a device side test from com.android.server.pm.test.deviceside.DeviceSide
|
||||
*
|
||||
* @param method the method to run
|
||||
*/
|
||||
fun runDeviceTest(testClassName: String, method: String) {
|
||||
val deviceSideFile = HostUtils.copyResourceToHostFile(DEVICE_SIDE, tempFolder.newFile())
|
||||
Truth.assertThat(device.installPackage(deviceSideFile, true)).isNull()
|
||||
runDeviceTests(device, "com.android.server.pm.test.deviceside",
|
||||
testClassName, method)
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,8 @@ android_test_helper_app {
|
||||
],
|
||||
static_libs: [
|
||||
"androidx.annotation_annotation",
|
||||
"commands-helper",
|
||||
"cts-install-lib",
|
||||
"junit",
|
||||
"junit-params",
|
||||
"androidx.test.ext.junit",
|
||||
|
||||
@@ -19,6 +19,8 @@
|
||||
package="com.android.server.pm.test.deviceside">
|
||||
|
||||
<uses-permission android:name="android.permission.QUERY_ALL_PACKAGES" />
|
||||
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
|
||||
<uses-permission android:name="android.permission.DELETE_PACKAGES" />
|
||||
|
||||
<instrumentation
|
||||
android:name="androidx.test.runner.AndroidJUnitRunner"
|
||||
|
||||
@@ -0,0 +1,120 @@
|
||||
/*
|
||||
* Copyright (C) 2021 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.android.server.pm
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Instrumentation
|
||||
import android.content.Context
|
||||
import android.system.helpers.CommandsHelper
|
||||
import androidx.test.platform.app.InstrumentationRegistry.getInstrumentation
|
||||
import com.android.compatibility.common.util.AdoptShellPermissionsRule
|
||||
import com.android.compatibility.common.util.SystemUtil
|
||||
import com.android.cts.install.lib.Install
|
||||
import com.android.cts.install.lib.InstallUtils
|
||||
import com.android.cts.install.lib.LocalIntentSender
|
||||
import com.android.cts.install.lib.TestApp
|
||||
import com.google.common.truth.Truth
|
||||
import org.junit.Rule
|
||||
import org.junit.Test
|
||||
import java.io.IOException
|
||||
import kotlin.jvm.JvmField
|
||||
|
||||
class PackageInstallerSessionTest {
|
||||
@Rule
|
||||
@JvmField
|
||||
val mAdoptShellPermissionsRule = AdoptShellPermissionsRule(
|
||||
getInstrumentation().getUiAutomation(),
|
||||
Manifest.permission.INSTALL_PACKAGES,
|
||||
Manifest.permission.DELETE_PACKAGES)
|
||||
|
||||
private val mInstrumentation: Instrumentation = getInstrumentation()
|
||||
private var mChildSessionStageDirInfo: String? = null
|
||||
|
||||
/**
|
||||
* To get all of child session IDs.
|
||||
*
|
||||
* @param parentSessionId the parent session id
|
||||
* @return the array of child session IDs
|
||||
* @throws IOException caused by opening parent session fail.
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
private fun getChildSessionIds(parentSessionId: Int): IntArray {
|
||||
InstallUtils.openPackageInstallerSession(parentSessionId).use {
|
||||
parentSession -> return parentSession.childSessionIds
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSessionStageDir(sessionId: Int): String? {
|
||||
val commandsHelper: CommandsHelper = CommandsHelper.getInstance(mInstrumentation)
|
||||
val dumpsysForPackage: MutableList<String>? = commandsHelper
|
||||
.executeShellCommandAndSplitOutput("dumpsys package", "\\n")
|
||||
val pattern = Regex(" stageDir=(\\S+${sessionId}\\S+) ")
|
||||
val matchStageDirs: ArrayList<String> = ArrayList()
|
||||
dumpsysForPackage?.forEach { line ->
|
||||
val matchResult: MatchResult? = pattern.find(line)
|
||||
if (matchResult != null) {
|
||||
val (stageDir: String) = matchResult.destructured
|
||||
matchStageDirs.add(stageDir)
|
||||
}
|
||||
}
|
||||
|
||||
if (matchStageDirs.size > 0) {
|
||||
return matchStageDirs[0]
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun getSessionStageDirInfo(sessionId: Int): String? {
|
||||
SystemUtil.runWithShellPermissionIdentity {
|
||||
val sessionStageDir =
|
||||
getSessionStageDir(sessionId) ?: return@runWithShellPermissionIdentity
|
||||
val command = "su root ls $sessionStageDir"
|
||||
val lines: List<String> = CommandsHelper.getInstance(mInstrumentation)
|
||||
.executeShellCommandAndSplitOutput(command, "\\n")
|
||||
val sessionIdStr = sessionId.toString()
|
||||
for (line in lines) {
|
||||
if (line.contains(sessionIdStr)) {
|
||||
mChildSessionStageDirInfo = line
|
||||
}
|
||||
}
|
||||
}
|
||||
return mChildSessionStageDirInfo
|
||||
}
|
||||
|
||||
@Test
|
||||
@Throws(Exception::class)
|
||||
fun verify_parentSessionFail_childSessionFiles_shouldBeDestroyed() {
|
||||
val context: Context = mInstrumentation.targetContext
|
||||
Install.single(TestApp.A3).commit()
|
||||
val parentSessionId: Int = Install.multi(TestApp.A1).createSession()
|
||||
val childSessionIds: IntArray = getChildSessionIds(parentSessionId)
|
||||
val firstChildSessionId = childSessionIds[0]
|
||||
|
||||
val sender = LocalIntentSender()
|
||||
try {
|
||||
InstallUtils.openPackageInstallerSession(parentSessionId).use { session ->
|
||||
session.commit(sender.intentSender)
|
||||
val result = sender.result
|
||||
InstallUtils.assertStatusFailure(result)
|
||||
}
|
||||
} finally {
|
||||
context.unregisterReceiver(sender)
|
||||
}
|
||||
|
||||
Truth.assertThat(getSessionStageDirInfo(firstChildSessionId)).isNull()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user