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. DNA Cloud, OEMConfig, StageNow, etc.)

Process Summary

  1. Create a Profile in the staging tool for deploying a file.
  2. Set the Profile to deploy using File Manager "Deploy a file for an application" File Action or the equivalent function.
  3. Enter the "Target Application File Definition" from the Zebra App Deployment Files table (below) corresponding to the file's Source* app.
  4. Enter the name of the signature file for the Source app (optional for StageNow deployment).
    Zebra recommends using Step 4 for added security. Learn more.
  5. Source Access Method: "File in the Device File System"
  6. Select Media type on a local Device: "Others"
  7. Enter File Name: Enter the "Source Path and File Name" for the app from the Zebra App Deployment Files table (below).

* The "Source" app is the Zebra app originating the file for sharing with others. Note: The source app can be the same app as the one consuming the shared file. For example, this is usually the case when deploying app-configuration 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