Symbian3/SDK/Source/GUID-DFF9DFC5-1BE0-5CA2-A2B9-27FA2DECFF59.dita
author Dominic Pinkman <dominic.pinkman@nokia.com>
Tue, 20 Jul 2010 12:00:49 +0100
changeset 13 48780e181b38
parent 0 89d6a7a84779
permissions -rw-r--r--
Week 28 contribution of SDK documentation content. See release notes for details. Fixes bugs Bug 1897 and Bug 1522.

<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (c) 2007-2010 Nokia Corporation and/or its subsidiary(-ies) All rights reserved. -->
<!-- This component and the accompanying materials are made available under the terms of the License 
"Eclipse Public License v1.0" which accompanies this distribution, 
and is available at the URL "http://www.eclipse.org/legal/epl-v10.html". -->
<!-- Initial Contributors:
    Nokia Corporation - initial contribution.
Contributors: 
-->
<!DOCTYPE task
  PUBLIC "-//OASIS//DTD DITA Task//EN" "task.dtd">
<task id="GUID-DFF9DFC5-1BE0-5CA2-A2B9-27FA2DECFF59" xml:lang="en"><title>Writing
an Active Backup Client Tutorial</title><shortdesc>A backup client application is often referred to as a data owner
as it owns the data. This section describes how to write an active backup
client which works with the Backup Engine and the Backup Server for data backup
and restore. </shortdesc><prolog><metadata><keywords/></metadata></prolog><taskbody>
<prereq id="GUID-B83C3258-BE3B-597F-A8EB-5598F059E2E3"><p>Before you start,
you must understand: </p> <ul>
<li id="GUID-909ACEA0-363B-585F-AAC7-D85706158930"><p><xref href="GUID-7FDD9FEC-5017-5E5D-A50A-5F343A3C7F6C.dita">Backup
Engine Concepts</xref> introduce the backup and restore types. </p> </li>
<li id="GUID-DB7C6BE8-A9A5-592F-BFD2-131FA7139BE2"><p><xref href="GUID-5CA933B9-7987-5DDE-AE12-B0D5AFD31451.dita">Symbian
Backup and Restore architecture</xref> describes the two ways of data backup
and restore. </p> </li>
<li id="GUID-E1A1DC99-39BC-59AD-A2A9-0261D6E689EB"><p><xref href="GUID-937C3D70-2DCC-5084-AC87-3B1E5865A827.dita">Active
Backup Client Architecture</xref> describes the components involved to do
active data backup and restore. </p> </li>
<li id="GUID-1FA3D484-3460-5A81-BD1E-52810746ECD8"><p><xref href="GUID-A81C65CF-CF4E-571C-8080-9D387F46AAD6.dita">Symbian
Publish and Subscribe</xref> describes how to publish and subscribe events
using properties. </p> </li>
</ul> </prereq>
<context id="GUID-06AB41B7-201A-5EB9-AFF2-1CF231B06118"><p>In an active backup
and restore, the Backup Engine calls the active backup client to supply the
data for the backup. Writing an active backup client means to: </p> <ul>
<li id="GUID-FAAB2D8E-14AD-5866-9D13-26D1DD39EBBC"><p>Create a user defined
class that has a data member pointer to <xref href="GUID-169BB4E2-5B0E-3719-A7B8-A3C0AAA602E2.dita#GUID-169BB4E2-5B0E-3719-A7B8-A3C0AAA602E2/GUID-17E48B80-2421-3256-B8B4-A0FED424D54A"><apiname>conn::CActiveBackupClient</apiname></xref>. </p> </li>
<li id="GUID-BB8DB868-66D9-5CE4-8CBD-0D9201365522"><p>Implement the <xref href="GUID-169BB4E2-5B0E-3719-A7B8-A3C0AAA602E2.dita#GUID-169BB4E2-5B0E-3719-A7B8-A3C0AAA602E2/GUID-DB245BC3-2ADA-311D-8024-B40335D22822"><apiname>conn::MActiveBackupDataClient</apiname></xref> interface. </p> </li>
</ul> </context>
<steps id="GUID-7D9E4BEE-5BBB-55B1-AB2C-C47E176B0CE7">
<step id="GUID-95BE7D7F-D355-5CC9-9A02-3351FBC8E709"><cmd/>
<info>Write an active backup client (data owner) class which must subscribe
for the <codeph>KUidBackupRestoreKey</codeph> property published by the backup
server. </info>
<info>When a backup server receives a request from a client (a host PC) for
a backup or a restore, it reads backup registration files for a list of data
owners (refer to step 3). It then calls the <codeph>CSBEClient::SetBURModeL()</codeph> function
with the registered types (base or incremental, full or partial). This function
signals start or completion of a backup or restore to all data owners. Data
owners must subscribe the following publish and subscribe property: </info>
<substeps id="GUID-29550A41-94C4-5F36-9175-B0FDF2E55483">
<substep id="GUID-E291A40F-9573-52D7-833D-DDCA3F194B59"><cmd/>
<info>Key–<codeph>KUidBackupRestoreKey</codeph> defined in the <filepath>epoc32\include\connect\sbdefs.h</filepath> header
file. This key belongs to the <codeph>KUidSystemCategoryValue</codeph> category. </info>
</substep>
<substep id="GUID-774E7565-EB05-5302-B7C7-BD25F6CAFAE0"><cmd/>
<info>Value–<codeph>TBURPartType</codeph> or <codeph>TBackupIncType</codeph>. </info>
</substep>
</substeps>
<info>The backup client must check the value of the property (flag) on startup,
in case the device is already in a backup or restore mode. A <xref href="GUID-169BB4E2-5B0E-3719-A7B8-A3C0AAA602E2.dita#GUID-169BB4E2-5B0E-3719-A7B8-A3C0AAA602E2/GUID-17E48B80-2421-3256-B8B4-A0FED424D54A"><apiname>conn::CActiveBackupClient</apiname></xref> object
can only be created once the publish and subscribe flag has transitioned into
a backup or restore mode. The backup client can be deleted once the backup
or restore operation has finished. This releases valuable system resources. </info>
<info> <codeph>CActiveBackupClient::ConfirmReadyForBURL()</codeph> is called
to indicate that the backup client is ready for the data supply to the Backup
Engine. </info>
<stepxmp><codeblock id="GUID-179BD485-939F-5D89-A123-55FDB8815140" xml:space="preserve">class CReferenceActiveDataOwner : public CActive
    {
    // Methods
public:
    static CReferenceActiveDataOwner* NewL();
    ~CReferenceActiveDataOwner();
    
    // From CActive
    void RunL();
    TInt RunError(TInt aError);
    void DoCancel();

private:
    CReferenceActiveDataOwner() 
    void ConstructL();
    void SubscribeToPSFlag();
    void ProcessBackupStateL(TInt aBackupStateValue);

    // Attributes
private:
    //Active Backup Client
    CActiveBackupClient* iActiveBackupClient;
    
    //The publish and subscribe flag from the Backup Engine
    RProperty iProperty;
    
    //Pointer to the callback implementation
    CReferenceCallbackImplementation* iCallbackImpl;
    };
    
/** Subscribe to the publish and subscribe flag.
    Call RunL() when the flag changes.
*/
void CReferenceActiveDataOwner::SubscribeToPSFlag()
    {
    iStatus = KRequestPending;
    iProperty.Subscribe(iStatus);
    SetActive();
    }

/** Check the flag in case the data owner has been started for a backup or restore, 
    or in case the publish and subscribe transition is missed.
*/
void CReferenceActiveDataOwner::ConstructL()
    {
    // Set up the property to catch the flag.
    TInt backupStateValue = 0;
    iProperty.Attach(KUidSystemCategory, KUidBackupRestoreKey);

    // Process the mode change accordingly
    iProperty.Get(backupStateValue);
    ProcessBackupStateL(backupStateValue);

    // Add to the active scheduler
    CActiveScheduler::Add(this);

    // Subscribe to the flag to catch transitions
    SubscribeToPSFlag();    
}

/** Create the CActiveBackupClient and the callback implementation
    based on the flag.
@param aBackupStateValue the new backup state value
*/
void CReferenceActiveDataOwner::ProcessBackupStateL(TInt aBackupStateValue)
    {
    TInt type = aBackupStateValue &amp; KBURPartTypeMask;
    
    // Create the the CActiveBackupClient and the callback implementation if
    // the device is in a backup or a restore mode.
    if (type == EBURBackupFull || type == EBURRestoreFull ||
        type == EBURBackupPartial || type == EBURRestorePartial)
        if (iCallbackImpl == NULL)
            {
            iCallbackImpl = CReferenceCallbackImplementation::NewL();
            }
        if (iActiveBackupClient == NULL)
            {
            iActiveBackupClient = 
                      CActiveBackupClient::NewL(iCallbackImpl);
            }
        }

    // Confirm the readiness of the active backup client.
    if ((type == EBURBackupFull || type == EBURRestoreFull) ||
        ((type == EBURBackupPartial || type == EBURRestorePartial) &amp;&amp;
         iActiveBackupClient-&gt;DoesPartialBURAffectMeL()))
        {

         .... // Things handled by a device vendor.

        //Inform the Backup Engine that the client is ready for data supply.
        iActiveBackupClient-&gt;ConfirmReadyForBURL(KErrNone);
        }
    else        
        {
        // CActiveBackupClient and the callback implementation 
        // if it is not an active backup.
        if (iActiveBackupClient != NULL)
            {
            delete iActiveBackupClient;
            iActiveBackupClient = NULL;
            }

        // The callback implementation must be deleted after 
        // the CActiveBackupClient is deleted.
        if (iCallbackImpl != NULL)
            {
            delete iCallbackImpl;
            iCallbackImpl = NULL;
            }
        }
    }

/** When the flag changes, RunL() is called.
*/
void CReferenceActiveDataOwner::RunL()
    {
 
    TInt backupStateValue = 0;   // re-set the flag value

    // re-subscribe to the flag to monitor future changes
    SubscribeToPSFlag();

    iProperty.Get(backupStateValue);

    // Process the mode change accordingly
    ProcessBackupStateL(backupStateValue);
    }

...
</codeblock> </stepxmp>
</step>
<step id="GUID-E17042E5-A5FE-56DF-A36C-594B4B5451B2"><cmd/>
<info>Implement <xref href="GUID-169BB4E2-5B0E-3719-A7B8-A3C0AAA602E2.dita#GUID-169BB4E2-5B0E-3719-A7B8-A3C0AAA602E2/GUID-DB245BC3-2ADA-311D-8024-B40335D22822"><apiname>conn::MActiveBackupDataClient</apiname></xref> to write
a callback handler. </info>
<info>The callback handler prepares the data to the Backup Engine for a backup
or a restore. For more information about each function, refer to the <xref href="GUID-169BB4E2-5B0E-3719-A7B8-A3C0AAA602E2.dita#GUID-169BB4E2-5B0E-3719-A7B8-A3C0AAA602E2/GUID-DB245BC3-2ADA-311D-8024-B40335D22822"><apiname>conn::MActiveBackupDataClient</apiname></xref> API
reference. The callback implementation must fulfill the following requirements: </info>
<substeps id="GUID-90CAC68A-4EDF-5B09-865B-DDDA5128780A">
<substep id="GUID-30B4E7CC-C5E2-5E37-B8B8-C110953D88FF"><cmd/>
<info>The Initialise function is usually called before the actual backup or
restore function is called. For example, <codeph>InitialiseGetBackupDataL()</codeph> is
called before <codeph>GetBackupDataSectionL()</codeph>. The Initialise function
gives a chance to a device vendor to prepare the data before the actual data
supply. </info>
</substep>
<substep id="GUID-661B4417-F1E4-5000-AA64-13BAFDB43234"><cmd/>
<info>In an incremental backup or restore, a snapshot is the dataset after
each incremental backup or restore. If <codeph>MActiveBackupDataClient::AllSnapshotsSuppliedL()</codeph> is
called, it means that all snapshots have been supplied to the <xref href="GUID-169BB4E2-5B0E-3719-A7B8-A3C0AAA602E2.dita#GUID-169BB4E2-5B0E-3719-A7B8-A3C0AAA602E2/GUID-17E48B80-2421-3256-B8B4-A0FED424D54A"><apiname>conn::CActiveBackupClient</apiname></xref>.
If <xref href="GUID-169BB4E2-5B0E-3719-A7B8-A3C0AAA602E2.dita#GUID-169BB4E2-5B0E-3719-A7B8-A3C0AAA602E2/GUID-17E48B80-2421-3256-B8B4-A0FED424D54A"><apiname>conn::CActiveBackupClient</apiname></xref> does not receive a snapshot,
it performs a base backup. </info>
</substep>
<substep id="GUID-03A009F5-7E05-5FBE-867A-13F8B93E66E5"><cmd/>
<info>For a backup function, a <xref href="GUID-4B942C06-1BAC-3A21-B3B1-89FB5C51ADA0.dita"><apiname>TBool</apiname></xref> reference parameter
named <codeph>aFinished</codeph> is passed as an argument. This indicates
to the Backup Engine if all of the data for a backup is supplied. Setting
this to <xref href="GUID-A759CA2D-8327-348F-9337-4886E619D920.dita"><apiname>EFalse</apiname></xref> causes the Backup Engine to repeatedly call
the backup function for more data. </info>
</substep>
<substep id="GUID-174C6057-A621-542E-A1C2-0F3879B4291D"><cmd/>
<info>For a restore function, <codeph>aFinished</codeph> is passed from the
Backup Engine to indicate to the data owner if all of the restore data is
supplied. The Backup Engine sets <codeph>aFinished</codeph> to <xref href="GUID-781E8158-805B-3784-8FED-D7A191822FC3.dita"><apiname>ETrue</apiname></xref> after
the final call of the restore function. </info>
</substep>
<substep id="GUID-26C220A3-2B91-575F-BA73-C19AD7A836E0"><cmd/>
<info>Any leaves in the callback are propagated over Inter-Processor Communications
(IPC) to the Backup Engine and potentially to the PC as errors. For this reason,
any internal calls must be trapped in the callback. </info>
</substep>
</substeps>
<stepxmp><codeblock id="GUID-E20C5B20-8956-50AB-98A8-3FAF1B98B925" xml:space="preserve">class CReferenceCallbackImplementation :
    public CBase,
    public MActiveBackupDataClient
    {
    // Methods
public:
    static CReferenceCallbackImplementation* NewL();
    ~CReferenceCallbackImplementation();

    // The following functions are from the MActiveBackupDataClient  
    void AllSnapshotsSuppliedL();
    void ReceiveSnapshotDataL(TDriveNumber aDrive, TDesC8&amp; aBuffer, 
                                TBool aLastSection);
    TUint GetExpectedDataSize(TDriveNumber aDrive);
    void GetSnapshotDataL(TDriveNumber aDrive, TPtr8&amp; aBuffer, 
                            TBool&amp; aFinished);
    void InitialiseGetBackupDataL(TDriveNumber aDrive);
    void GetBackupDataSectionL(TPtr8&amp; aBuffer, TBool&amp; aFinished);
    void InitialiseRestoreBaseDataL(TDriveNumber aDrive);
    void RestoreBaseDataSectionL(TDesC8&amp; aBuffer, TBool aFinished);
    void InitialiseRestoreIncrementDataL(TDriveNumber aDrive);
    void RestoreIncrementDataSectionL(TDesC8&amp; aBuffer, TBool aFinished);
    void RestoreComplete(TDriveNumber aDrive);
    void TerminateMultiStageOperation();
    TUint GetDataChecksum(TDriveNumber aDrive);

    //The following two functions are for the proxy backup client only and 
    // Symbian provides a default implementation for each function.
    void InitialiseGetProxyBackupDataL(TSecureId aSID, TDriveNumber aDrive);
    void InitialiseRestoreProxyBaseDataL(TSecureId aSID, TDriveNumber aDrive);
    
private:
    CReferenceCallbackImplementation() {}        
    CMyABData* iSnapshot;
    CMyABData* iData;
    TBool iProxy;
    TInt iOffset;
    TInt iSourceSize;
    TUint iFillChar;
    TSecureId iID;
    };

void CReferenceCallbackImplementation::AllSnapshotsSuppliedL()
    {
    __LOG1("[0x%08x]: CReferenceCallbackImplementation::AllSnapshotsSuppliedL()", 
         iID.iId);
    }
    
void CReferenceCallbackImplementation::ReceiveSnapshotDataL(
                                           TDriveNumber aDrive, 
                                           TDesC8&amp; aBuffer,
                                           TBool /*aLastSection*/)
    {
    __LOG1("[0x%08x]: CReferenceCallbackImplementation::ReceiveSnapshotDataL()", iID.iId);
    // Create or append a buffer containing the snapshot
    if (!iSnapshot)
        {
        iSnapshot = CMyABData::NewL(aDrive);
        }

    iSnapshot-&gt;AddDataL(aBuffer);
    }
    
TUint CReferenceCallbackImplementation::GetExpectedDataSize(TDriveNumber /*aDrive*/)
    {
    __LOG1("[0x%08x]: CReferenceCallbackImplementation::GetExpectedDataSize()", iID.iId);
        
    return iSourceSize;
    }
    
void CReferenceCallbackImplementation::GetSnapshotDataL(
                                           TDriveNumber /*aDrive*/,
                                           TPtr8&amp; aBuffer,
                                           TBool&amp; aFinished)
    {
    __LOG1("[0x%08x]: CReferenceCallbackImplementation::GetSnapshotDataL()", iID.iId);
    aBuffer.Append(KABTestSnapshot());
    
    aFinished = ETrue;
    }
    
void CReferenceCallbackImplementation::InitialiseGetBackupDataL(TDriveNumber /*aDrive*/)
    {
    __LOG1("[0x%08x]: CReferenceCallbackImplementation::InitialiseGetBackupData()", iID.iId);
    iOffset = 0;

    if (!iSnapshot)
        {
        iFillChar = 66;
        }
    else
        {
        iFillChar = 73;
        }
    }
    
void CReferenceCallbackImplementation::GetBackupDataSectionL(
                                            TPtr8&amp; aBuffer,
                                            TBool&amp; aFinished)
    {
    __LOG1("[0x%08x]: CReferenceCallbackImplementation::GetBackupDataSectionL()", iID.iId);
    
    FillBuffer(aBuffer, aFinished);
    }
    
void CReferenceCallbackImplementation::InitialiseRestoreBaseDataL(TDriveNumber aDrive)
    {
    __LOG("CReferenceCallbackImplementation::InitialiseRestoreBaseDataL()");

    iData = CMyABData::NewL(aDrive);
    }
    
void CReferenceCallbackImplementation::RestoreBaseDataSectionL(
                                           TDesC8&amp; aBuffer,
                                           TBool aFinished)
    {
    __LOG1("[0x%08x]: CReferenceCallbackImplementation::RestoreBaseDataSectionL()", iID.iId);

    // append a buffer containing the base data
    iData-&gt;AddDataL(aBuffer);
    
    if (aFinished)
        {
        ValidateRestoredData();
    
        delete iData;
        iData = NULL;
        }
    }
    
void CReferenceCallbackImplementation::InitialiseRestoreIncrementDataL(TDriveNumber aDrive)
    {
    __LOG1("[0x%08x]: CReferenceCallbackImplementation::InitialiseRestoreIncrementDataL()", iID.iId);
    if (!iSnapshot)
        {
        User::Leave(KErrCorrupt);
        }

    if (!iData)
        {
        iData = CMyABData::NewL(aDrive);
        }
    }
    
void CReferenceCallbackImplementation::RestoreIncrementDataSectionL(
                                           TDesC8&amp; aBuffer,
                                           TBool aFinished)
    {
    __LOG1("[0x%08x]: CReferenceCallbackImplementation::RestoreIncrementDataSectionL()", iID.iId);

    iData-&gt;AddDataL(aBuffer);
    
    if (aFinished)
        {
        ValidateRestoredData();
    
        delete iData;
        iData = NULL;
        }
    }
    
void CReferenceCallbackImplementation::RestoreComplete(TDriveNumber /*aDrive*/)
    {
    __LOG1("[0x%08x]: CReferenceCallbackImplementation::RestoreComplete()", iID.iId);
    }
    
void CReferenceCallbackImplementation::TerminateMultiStageOperation()
    {
    __LOG1("[0x%08x]: CReferenceCallbackImplementation::TerminateMultiStageOperation()", iID.iId);
    // We also don't do anything here until we start testing multipart?
    }
    
TUint CReferenceCallbackImplementation::GetDataChecksum(TDriveNumber /*aDrive*/)
    {
    __LOG1("[0x%08x]: CReferenceCallbackImplementation::GetDataChecksum()", iID.iId);
    return 0;
    }

void CReferenceCallbackImplementation::InitialiseGetProxyBackupDataL(
                                           TSecureId aSID, 
                                           TDriveNumber /*aDrive*/)
    {
    __LOG1("[0x%08x]: CReferenceCallbackImplementation::InitialiseGetProxyBackupDataL()", iID.iId);
    __LOG2("[0x%08x]: Proxy data about to be requested for SID 0x%08x", iID.iId, aSID.iId);
    iProxy = ETrue;
    iOffset = 0;
    
    iFillChar = 80;        // 'P'
    }

void CReferenceCallbackImplementation::InitialiseRestoreProxyBaseDataL(
                                            TSecureId aSID, 
                                            TDriveNumber aDrive)
    {
    __LOG1("[0x%08x]: CReferenceCallbackImplementation::InitialiseRestoreProxyBaseDataL()", iID.iId);
    __LOG2("[0x%08x]: Proxy data about to be restored for SID 0x%08x", iID.iId, aSID.iId);
    iProxy = ETrue;
    iData = CMyABData::NewL(aDrive);
    }
...</codeblock> </stepxmp>
</step>
<step id="GUID-FBC19F0B-1763-595C-BF4E-F6289AD6EFCA"><cmd/>
<info>Create a backup registration file to set attribute values for the data
owner application. </info>
<info>The Backup Engine parses backup registration files to get the data own
list. The list includes details of data owners and data for backup and restore. </info>
<info>Create the file using a text editor and save it as <filepath>backup_registration.xml</filepath> under
the private folder of the data owner application on the Symbian device. Refer
to <xref href="GUID-9A6273D8-7797-5190-AFEC-1AD113980B84.dita">Backup Registration
Files</xref> for more information. </info>
<substeps id="GUID-08064C91-CC63-502F-807C-D1932C0D05DB">
<substep id="GUID-D2C54ED8-54C5-564A-B5DF-66CC60F85630"><cmd/>
<info> <codeph> process_name</codeph> is the name of the data owner application. </info>
</substep>
<substep id="GUID-20E42C15-0B8C-5302-8927-1ADB9231AC33"><cmd/>
<info> <codeph>active_type is set</codeph> to <codeph>activeonly</codeph> for
an active backup. </info>
</substep>
<substep id="GUID-595FE2CF-06C4-599F-9E70-B9B9CD6A71B5"><cmd/>
<info> <codeph>supports_incremental</codeph> can be set to <codeph>false</codeph> to
disable the incremental backup support from the active backup client. </info>
</substep>
</substeps>
<stepxmp><codeblock id="GUID-0A5E0FBC-16FD-568A-8530-368101B28EBF" xml:space="preserve">&lt;!-- backup_registration.xml file for referencetestdataowner.exe --&gt;

&lt;?xml version="1.0" standalone="yes"?&gt;

&lt;backup_registration version="1.0"&gt;
    &lt;active_backup process_name = "referencetestdataowner.exe"
             active_type = "activeonly"
                   requires_delay_to_prepare_data = "yes" &lt;!--deprecated--&gt;
                   supports_incremental = "yes"&gt; 
    &lt;/active_backup&gt;

    &lt;restore requires_reboot = "no"/&gt;  &lt;!--Currently only support no--&gt;
&lt;/backup_registration&gt;
</codeblock><p>Finally, test the data owner application. The logging information
appends to the <filepath>securebackup.txt</filepath> log file. To enable the
log generation, the <filepath>C:\logs\connect</filepath> directory must be
created on the device. </p> </stepxmp>
</step>
</steps>
</taskbody></task>