Using SSM with Zebra Apps

Secure Storage Manager 1.1

Overview

This guide describes how to use Secure Storage Manager (SSM) for secure deployment of files for configuring Zebra apps and/or sharing data. Files can be deployed for use by other apps (or by the originating app itself) either through Zebra OEMConfig and StageNow, a company's own EMM or programmatically from within an application.

Requirements

  • Zebra device(s) running Android 11 (or later)
  • Zebra MX 11.3 (or later) on device (Which version is present?)
  • A staging tool (e.g. OEMConfig, StageNow, EMM, etc.)

Process Summary

  1. Create a Profile (in OEMConfig, StageNow, EMM, etc.) that deploys a file.
  2. Set the Profile to deploy using File Manager "Deploy a file for an application" File Action (requires MX 11.3 or later).
  3. Enter the Target Application File Definition from the Zebra App Deployment Files table (below) corresponding to the file Source* app.
  4. Enter the name of the signature file for the Source app (optional for StageNow deployment)
    Zebra recommends this step for added security. Learn more.
  5. For Source Access Method: Select "File in the Device File System"
  6. For Select Media type on a local Device: select "Others"
  7. For Enter File Name: Enter the Source Path and File Name_†_ from the Zebra App Deployment Files table (below)

* The "Source" app is the Zebra app that's originating the file for sharing with others. Note that the Source app can be the same app as the one consuming the shared file, such as with many app-config files.

† Where appropriate, replace the example file name with the chosen file name.

Also See



Deploy via Application

This section describes how to use SSM to securely deploy a file to a device. A DataWedge Profile is used as an example.

In the app's AndroidManifest.xml file:

  1. Add the following permissions:

    <uses-permission android:name="com.zebra.securestoragemanager.securecontentprovider.PERMISSION.WRITE" />
    <uses-permission android:name="com.zebra.securestoragemanager.securecontentprovider.PERMISSION.READ" />
    
  2. Add the following queries to allow the app to interact with SSM:

    <queries>
        <package android:name="com.zebra.securestoragemanager" />
        <provider android:authorities="com.zebra.securestoragemanager.securecontentprovider"/>
    </queries>
    
  3. Add the following code to define a FileProvider that allows the app to grant read permissions to files. Replace com.app.package.name with the package name of the app.

    <provider
        android:name="androidx.core.content.FileProvider"
        android:authorities="com.your.package.name.provider"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/provider_paths"/>
    </provider>
    

In the app's project:

  1. In the "xml" subfolder under the "res" parent folder, add a file named provider_paths.xml with the following content:

    <?xml version="1.0" encoding="utf-8"?>
        <paths xmlns:android="http://schemas.android.com/apk/res/android">
        <root-path path="/data/tmp/public" name="public"/>
        <root-path path="/enterprise/usr"  name="user"/>
        <external-path path="." name="external_files"/>
        <files-path path="." name="template"/>
    </paths>
    
  2. Create a directory (e.g. ConfigDBs) inside the "assets" folder and copy the DataWedge Profile and/or config file within this folder: image

  3. In the app, add a function called uploadTemplates(), which copies files from the "assets" directory and uploads them via the copy function copyFileViaSSM().

    
    public void uploadConfigDB(boolean isFullDB) {
    
    
    AssetManager assetManager = getAssets();
    String[] files = null;
    
    try {
        files = assetManager.list(ASSET_DB_DIR);
    } 
    catch (IOException e) {
        Log.e(TAG, "Failed to get asset file list: " + e.getMessage());
    }
    
    if (files != null) {
    
        for (String filename : files) {
    
            if (isFullDB &amp;&amp; filename.equals("datawedge.db"))
            {
                integrateFile(assetManager, filename);
            } 
            else if (!isFullDB &amp;&amp; filename.startsWith("dwprofile_"))
            {
                integrateFile(assetManager, filename);
            }
        }
    } 
    else {
        Log.d(TAG, "asset file list is null");
    }
    
    } private void integrateFile(AssetManager assetManager, String filename) { InputStream in = null; OutputStream out = null;
    try {
        in = assetManager.open(ASSET_DB_DIR + "/" + filename);
    
        String outDir = getFilesDir().getAbsolutePath() + "/";
        File outFile = new File(outDir, filename);
    
        out = new FileOutputStream(outFile);
    
        copyFile(in, out);
        in.close();
        out.flush();
        out.close();
    
        copyFileViaSSM(outFile.getAbsolutePath(), "config");
    
    } 
    catch (IOException e) {
        Log.e("tag", "Failed to copy asset file: " + filename, e);
    }
    
    } private void copyFile(InputStream in, OutputStream out) throws IOException { byte[] buffer = new byte[1024]; int read; while ((read = in.read(buffer)) != -1) { out.write(buffer, 0, read); } } public void copyFileViaSSM(String sourcePath, String type) {
    File file = new File(sourcePath);
    
    Uri contentUri = FileProvider.getUriForFile(this, this.getPackageName() + ".provider", file);
    
    this.getApplicationContext().grantUriPermission("com.zebra.securestoragemanager", contentUri, Intent.FLAG_GRANT_READ_URI_PERMISSION); // Needed to grant permission for SSM to read the uri
    
    Uri cpUriQuery = Uri.parse(AUTHORITY_FILE + this.getPackageName());
    
    try {
        ContentValues values = new ContentValues();
        values.put("target_app_package", String.format("{\"pkgs_sigs\": [{\"pkg\":\"%s\",\"sig\":\"%s\"}]}", "com.symbol.datawedge", signature));
        values.put("data_name", String.valueOf(contentUri)); // Passes the content uri as a input source
        values.put("data_type", "3");
        values.put("data_value", "com.symbol.datawedge/" + type + "/" + file.getName()); // Replace “targetPath” with the package name of the target app that is accessing the deployed file (or retrieve the app package using context.getPackageName()) followed by "/" and the full path of the file, e.g. "context.getPackageName()/A.txt"
    
        values.put("data_persist_required", false);
        Uri createdRow = this.getContentResolver().insert(cpUriQuery, values);
        Log.i(TAG, "SSM Insert File: " + createdRow.toString());
    
    } 
    catch (Exception e) {
        Log.e(TAG, "SSM Insert File - error: " + e.getMessage() + "\n\n");
    }
    
    }
  4. Call the method uploadConfigDB(boolean isFullDB) to upload the configuration DB files from the asset folder to DataWedge.

    • If uploading a full configuration DB, pass "true" for the "isFullDB" parameter
    • If uploading a profile DB, pass "false" for the "isFullDB" parameter

Zebra App Deployment Files

Use the values below to deploy, share or consume files between and among Zebra apps on a device.


Also See