Start activity with adb - android

I have a simplest possible test app, developed with xamarin, deployed to a usb connected droid. With the goal of having one day a working intent url, I'm trying to call my main activity with adb shell am. Here are the first few lines of my MainActivity...
namespace DematAEAT_Android
{
[Activity(Label = "DematAEAT_Android", MainLauncher = true, Icon = "#drawable/icon")]
[IntentFilter(new[] { "AcquireSignedImage" },
Categories = new[] { Intent.CategoryBrowsable, Intent.CategoryDefault })]
public class MainActivity : Activity
{
int count = 1;
Here are two shell commands. In the first, the package manager successfully understands the package name and reports the apk path. In the second, the activity manager fails to resolve the class MainActivity. It fails with or without the namespace.
C:\Program Files (x86)\Android\android-sdk\platform-tools>adb -d shell pm path "fr.company.DematAEAT_Android"
package:/data/app/fr.company.DematAEAT_Android-1/base.apk
C:\Program Files (x86)\Android\android-sdk\platform-tools>adb -d shell am start -n "fr.company.DematAEAT_Android/.DematAEAT_Android.MainActivity"
Starting: Intent { cmp=fr.company.DematAEAT_Android/.DematAEAT_Android.MainActivity }
Error type 3
Error: Activity class {fr.company.DematAEAT_Android/fr.company.DematAEAT_Android.DematAEAT_Android.MainActivity} does not exist.
edit...
And yet, I can launch happily using monkey. The following command works fine. Tis as if there's a problem with the way I'm naming my activity class in the adb shell am call, but I can't spot it.
C:\Program Files (x86)\Android\android-sdk\platform-tools>adb shell monkey -p fr.company.DematAEAT_Android 1
Events injected: 1
## Network stats: elapsed time=170ms (0ms mobile, 0ms wifi, 170ms not connected)
Can anyone tell me how to call this activity?

This was a breaking change in Xamarin Android 5.0
Android Callable Wrapper Naming
The name mangling scheme for Android Callable Wrappers is changing. Previously, the Android Callable Wrapper package name was constructed by lowercasing the namespace name, which would result in packaging failures if more than one assembly contained a type with the same fully-qualified name.
With the 5.0 release, the default package names for Android Callable Wrappers will be based on the MD5SUM of the assembly-qualified name of the type being exported. This allows the same fully-qualified name to be provided from two different assemblies and not get a packaging error.
https://developer.xamarin.com/releases/android/xamarin.android_5/xamarin.android_5.1/#Android_Callable_Wrapper_Naming
You can override that for your Activity by specifying the name in the [Activity] attribute:
[Activity(Name = "fr.company.demeat_android.MainActivity")]
public class MainActivity : Activity {
/* ... */
}

Well who knew? I needed to grub around in my manifest.xml to discover that xamarin is appending a hash as a namespace in front of my activity name. So the adb call that works looks like this...
C:\Program Files (x86)\Android\android-sdk\platform-tools>adb -d shell am start -n fr.company.DematAEAT_Android/md5abda05033ab0415fc7a776c5d9734c74.BrowsableActivity
Starting: Intent { cmp=fr.company.DematAEAT_Android/md5abda05033ab0415fc7a776c5d9734c74.BrowsableActivity }
The story continues here. This will likely be an issue for anyone trying to start a xamarin activity via adb shell am, or trying to start a xamarin activity with an intent, or an intent url.

Related

Declare service in AOSP

As part of a training course I need to declare a service in AOSP and call it at boot. The thing is the training is outdated, I'm working on a physical machine and the project is different.
Specs:
Android Version: 12
Android SDK: 31
Anyway I've built a module in C called "exd", it's stored in /system/bin/ and it works properly when called manually. Next I want to declare it as a service.
I've added to init.product.rc file:
service exd /system/bin/exd
oneshot
on boot
start exd
But when I build and download it to the device, service list doesn't display it. And it doesn't start on boot.
Next I've added exd.te file to sepolicy folder:
type exd, domain;
type exd_exec, domain;
init_daemon_domain(exd)
And added this line to file_contexts:
/system/bin/exd u:object_r:exd_exec:s0
When I call build it fails with the following message:
Error while expanding policy
[ 39% 60/151] //system/sepolicy:sepolicy.recovery Compiling cil files for sepolicy.recovery [common]
FAILED: out/soong/.intermediates/system/sepolicy/sepolicy.recovery/android_common/sepolicy
out/host/linux-x86/bin/secilc -m -M true -G -c 30 out/soong/.intermediates/system/sepolicy/recovery_sepolicy.cil/android_common/recovery_sepolicy.cil -o out/soong/.intermediates/system/sepolicy/sepolicy.recovery/android_common/sepolicy_policy -f /dev/null && cp -f out/soong/.intermediates/system/sepolicy/sepolicy.recovery/android_common/sepolicy_policy out/soong/.intermediates/system/sepolicy/sepolicy.recovery/android_common/sepolicy && rm -f out/soong/.intermediates/system/sepolicy/sepolicy.recovery/android_common/sepolicy_policy # hash of input list: 187605db6ee3f7580bafd9adbd0101d2c2a0d02f423bb7efa74ee537c43d35ce
neverallow check failed at out/soong/.intermediates/system/sepolicy/recovery_sepolicy.cil/android_common/recovery_sepolicy.cil:8770 from system/sepolicy/public/domain.te:1240
(neverallow base_typeattr_197 domain (file (execute execute_no_trans entrypoint)))
<root>
allow at out/soong/.intermediates/system/sepolicy/recovery_sepolicy.cil/android_common/recovery_sepolicy.cil:28846
(allow init exd_exec (file (read getattr map execute open)))
<root>
allow at out/soong/.intermediates/system/sepolicy/recovery_sepolicy.cil/android_common/recovery_sepolicy.cil:28848
(allow exd exd_exec (file (read getattr map execute open entrypoint)))
Failed to generate binary
Failed to build policydb
10:35:34 ninja failed with: exit status 1
I've tried everything I've found on the internet to no avail. The weird thing is that there is another service called "bugreport" which is declared almost indetically as mine, but it is listed after "service list" command.
At this point even pointing a good direction would be great for me.
You are getting neverallow, which is basically Android saying you are trying to do something that is not allowed in the SEPolicy definition. You need to create a .te file that consists of SEPolicy rules for your service.
An example SEPolicy file can be as follows:
type myservice_exec, exec_type, file_type, system_file_type;
typeattribute myservice coredomain;
# myservice servicemanager and binder access
allow shell myservice:binder { call transfer };
allow servicemanager myservice:dir search;
allow servicemanager myservice:file { open read };
allow servicemanager myservice:process getattr;
allow myservice servicemanager:binder { call transfer};
allow myservice system_server:binder call;
init_daemon_domain(myservice)
Notice the second line. You are missing that and it is most probably why you are getting a neverallow problem.

How to initilaize connection of appium webdriver to a virtual android device that does nothing in Python?

I need an empty connection of webdriver to a virtual device in order to get an answer whether some application is already installed.
I try the following:
caps = {
'appium-version': '1.4.13',
'platformName': 'Android',
'platformVersion': '5.1',
'deviceName': 'Nexus 5',
'fullReset': 'false',
'androidPackage': 'com.android.launcher',
'appActivity': 'Launcher'
}
driver = webdriver.Remote('http://localhost:4723/wd/hub', caps)
#is_myapp_installed = driver.is_app_installed('com.my.app')
but get the following error:
WebDriverException: Message: A new session could not be created. (Original error: Activity used to start app doesn't exist or cannot be launched! Make sure it exists and is a launchable activity)
Give the corresponnding app activity and and package name
'androidPackage': 'com....packagename of your app',
'appActivity': 'launcheractivity of your app'
As the error clearly states the activity name your using doesn't exist which inherently means that ur session is established with the virtual device and its just waiting for a valid activity name to launch.
Let me know if your unable to find the activity of your app
Answering it newly since this adds another question in addition to your question.
There are multiple ways to find the activity of the app.
u can use aapt command in command prompt : aapt dump badging "full path to your apk"
the first line of the result will give the package name and go to the end of the result and find the launcher activity as shown below
NOTE: inorder for aapt command to work you android sdk build-tools folder should be set in PATH variable
You need to pass the proper app activity in code, which will be launched when app launches and appium looks for that activity.

Android tests are not executed

I have created a test project with exact the same code as shown here:
http://developer.android.com/tools/testing/testing_ui.html
I have uploaded the jar file in the android virtual device and now I'm ready to run the tests. But I always get this output on the console:
INSTRUMENTATION_STATUS: stream=
Test results for WatcherResultPrinter=
Time: 0.0
OK (0 tests)
INSTRUMENTATION_STATUS_CODE: -1
I have also created a simple test with the following code:
public void FailedTest() throws UiObjectNotFoundException {
assertTrue("This test was executed", false);
}
In case there is something wrong with the code using ui elements.
The package name is Tests and the class name Login so I run the following command:
adb shell uiautomator runtest TestProject.jar -c Tests.Login
Edit
When I run it on a real device I get:
uiautomator: permission denied
As a first step, can you change the name of the test method to match the standard convention used in jUnit 3 i.e. public void testWhatever() { ... } the first 4 letters of the name nust be 'test' in lower case, the signature is public void and the method does not take any parameters.
Similarly, can you change the package name to the more standard lowercase convention e.g. org.example.tests If you file is called Tests.java (and the class also called Tests) then you should be able to call it as follows:
adb shell uiautomator runtest Tests.jar -c com.example.tests.Tests
If these don't help, please can you revise the question to include the entire code from your Tests.java file?
Note: I've not tried to reproduce your code at this stage as I'm travelling. I can do so if my suggestions don't unblock your problem(s).
I'll follow up on the uiautomator: permission denied separately. UI Automator tests do run on real devices. They don't need the device to be rooted. I run them on standard Android 4.2.x devices.

How to run monkeyrunner on an already installed .apk

I'm trying to run some commands on an application that is already installed through monkeyrunner. I've edited the sample code listed on d.android.com and I changed it to this:
# Imports the monkeyrunner modules used by this program
from com.android.monkeyrunner import MonkeyRunner, MonkeyDevice
# Connects to the current device, returning a MonkeyDevice object
device = MonkeyRunner.waitForConnection()
# Installs the Android package. Notice that this method returns a boolean, so you can test
# to see if the installation worked.
device.installPackage('myproject/bin/MyApplication.apk')
# sets a variable with the package's internal name
package = 'com.example.myTestApp'
# sets a variable with the name of an Activity in the package
# activity = 'com.example.android.myapplication.MainActivity'
# sets the name of the component to start
runComponent = package
# Runs the component
device.startActivity(component=runComponent)
# Presses the Menu button
device.press('KEYCODE_MENU', MonkeyDevice.DOWN_AND_UP)
# Takes a screenshot
result = device.takeSnapshot()
# Writes the screenshot to a file
result.writeToFile('myproject/shot1.png','png')
As you can see, I changed the code to (hopefully) open com.example.myTestApp But it doesn't open my application, but it seems it runs the commands on the current application. Any ideas?
You should specify the Activity in runComponent as
runComponent = package + "/" + activity
To get the names of the launchable Activities:
$ aapt dump badging <name>.apk | grep launchable-activity
I was able to get the launch activity from an any installed apk from the play store using this method:
get launchable activity name of package from adb
adb shell pm list packages -f
Then you can use adb pull:
adb pull <APK path from previous command> <toYourDesiredLocation>
For Example:(adb pull /system/app/MyAPK.apk C:\someLocation)
and then aapt to get the information you want (aapt is currently located in ~\sdk\build-tools\android-4.3):
aapt dump badging <FromYourDesiredLocation\pulledfile.apk>
then look for launchable-activity: name='SomeActivityName'
Hope that helps someone else looking for the same thing.
First check whether your app is installed.
apk_path = device.shell('pm path com.xx.yy')
if apk_path.startswith('package:'):
print "XXXYY already installed."
else:
print "XXXYY app is not installed, installing APKs..."
device.installPackage('D:/path to apk/yourapp.apk')
refer http://antoine-merle.com/introduction-to-the-monkey-runner-tool-2/

Start an Android Test from an Intent (or from SL4A)?

I'd like to run some android tests but I want to scedule or delay the execution of these tests. I'm trying to do this from SL4A. The idea is to install SL4A start the server from my laptop, run a special python script that will sleep for about 20 seconds then wakeup and launch the tests. I am performing some rather involved automation that requires my tests be run after I install them and disconnect the USB cable. I know I can issue intents from SL4A but I'm looking for the equivalent of:
adb shell am instrument \
-e class MyInstrumentationTestCase \
-w MyInstrumentationTestRunner
Can this be done via intent? Should I send a broadcast or use the start activity functions?
I've tried running a system command directly on the device from Python with this script but I get a "permission denied" error:
from subprocess import call
call(["am", "instrument", "-e", "class", "com.example.android.app.test.TestContactList", "-w", "com.example.app.test/com.zutubi.android.junitreport.JUnitReportTestRunner"])
UPDATE
I've also tried using os.system to run the command (see below modifications) and this gives a different error: soinfo_link_image(linker.cpp:1635): could not load library "libanroid_runtime.so" needed by "app_process"; caused by so info_relocate(linker.cpp:975): cannot locate symbol " sqlite3_stmt_readonly" referenced by "lib android_runtime.so"...CANNOT LINK EXECUTABLE
import os
#from subprocess import call
#call(["am", "instrument", "-e", "class", "com.example.android.app.test.TestContactList", "-w", "com.example.android.app.test/com.zutubi.android.junitreport.JUnitReportTestRunner"])
os.system('echo "Running tests"')
os.system('am instrument -e class com.example.android.app.test.TestContactList -w com.example.android.app.test/com.zutubi.android.junitreport.JUnitReportTestRunner')
What are any other options?
I have the following function, which will launch any SL4A script from within a Python SL4A script, as a separate process. You can not use subprocess for this type of thing.
You may be able to deduce what you need from this.
from android import Android
droid = Android()
def launch_script(path, visible=False):
visibilty = 'FORE' if visible else 'BACK'
activity = 'com.googlecode.android_scripting.action.LAUNCH_{0}GROUND_SCRIPT'.format(visibilty)
extras = {'com.googlecode.android_scripting.extra.SCRIPT_PATH': path}
packagename = 'com.googlecode.android_scripting'
classname = 'com.googlecode.android_scripting.activity.ScriptingLayerServiceLauncher'
intent = droid.makeIntent(activity, None, None, extras, None, packagename, classname).result
droid.startActivityIntent(intent)

Categories

Resources